// parameters: // style 风格。如果为 GUI,表示会自动添加 Idle 事件,并在其中执行 Application.DoEvents public RmsChannel GetChannel( RmsChannelCollection channels, string strServerUrl) { if (_disabled) { return(null); } RmsChannel channel = channels.GetChannel(strServerUrl); this.Add(channel); // TODO: 检查数组是否溢出 return(channel); }
// 创建数据库 // parameters: // strLibraryCodeList 当前用户的管辖分馆代码列表 // bRecreate 是否为重新创建?如果为重新创建,则允许已经存在定义;如果不是重新创建,即首次创建,则不允许已经存在定义 // 注: 重新创建的意思, 是 library.xml 中有定义,但 dp2kernel 中没有对应的数据库,要根据定义重新创建这些 dp2kernel 数据库 int CreateDatabase( RmsChannelCollection Channels, string strLibraryCodeList, string strDatabaseInfo, bool bRecreate, out string strOutputInfo, out string strError) { strOutputInfo = ""; strError = ""; int nRet = 0; List<string> created_dbnames = new List<string>(); // 过程中,已经创建的数据库名 bool bDbChanged = false; // 数据库名是否发生过改变?或者新创建过数据库? 如果发生过,需要重新初始化kdbs XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strDatabaseInfo); } catch (Exception ex) { strError = "strDatabaseInfo内容装入XMLDOM时出错: " + ex.Message; return -1; } RmsChannel channel = Channels.GetChannel(this.WsUrl); XmlNodeList nodes = dom.DocumentElement.SelectNodes("database"); for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strType = DomUtil.GetAttr(node, "type").ToLower(); string strName = DomUtil.GetAttr(node, "name"); // 创建书目数据库 if (strType == "biblio") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建书目库"; return -1; } if (this.TestMode == true) { XmlNodeList existing_nodes = this.LibraryCfgDom.DocumentElement.SelectNodes("itemdbgroup/database"); if (existing_nodes.Count >= 4) { strError = "dp2Library XE 评估模式下只能创建最多 4 个书目库"; goto ERROR1; } } // 2009/11/13 XmlNode exist_database_node = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@biblioDbName='"+strName+"']"); if (bRecreate == true && exist_database_node == null) { strError = "library.xml中并不存在书目库 '"+strName+"' 的定义,无法进行重新创建"; goto ERROR1; } string strSyntax = DomUtil.GetAttr(node, "syntax"); if (String.IsNullOrEmpty(strSyntax) == true) strSyntax = "unimarc"; // usage: book series string strUsage = DomUtil.GetAttr(node, "usage"); if (String.IsNullOrEmpty(strUsage) == true) strUsage = "book"; // 2009/10/23 string strRole = DomUtil.GetAttr(node, "role"); if (bRecreate == false) { // 检查cfgdom中是否已经存在同名的书目库 if (this.IsBiblioDbName(strName) == true) { strError = "书目库 '" + strName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } // 检查dp2kernel中是否有和书目库同名的数据库存在 { // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } string strEntityDbName = DomUtil.GetAttr(node, "entityDbName"); string strOrderDbName = DomUtil.GetAttr(node, "orderDbName"); string strIssueDbName = DomUtil.GetAttr(node, "issueDbName"); string strCommentDbName = DomUtil.GetAttr(node, "commentDbName"); if (strEntityDbName == "<default>") strEntityDbName = strName + "实体"; if (strOrderDbName == "<default>") strOrderDbName = strName + "订购"; if (strIssueDbName == "<default>") strIssueDbName = strName + "期"; if (strCommentDbName == "<default>") strCommentDbName = strName + "评注"; string strInCirculation = DomUtil.GetAttr(node, "inCirculation"); if (String.IsNullOrEmpty(strInCirculation) == true) strInCirculation = "true"; // 缺省为true string strUnionCatalogStyle = DomUtil.GetAttr(node, "unionCatalogStyle"); string strReplication = DomUtil.GetAttr(node, "replication"); if (String.IsNullOrEmpty(strEntityDbName) == false) { if (bRecreate == false) { // 检查cfgdom中是否已经存在同名的实体库 if (this.IsItemDbName(strEntityDbName) == true) { strError = "实体库 '" + strEntityDbName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strEntityDbName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } if (String.IsNullOrEmpty(strOrderDbName) == false) { if (bRecreate == false) { // 检查cfgdom中是否已经存在同名的订购库 if (this.IsOrderDbName(strOrderDbName) == true) { strError = "订购库 '" + strOrderDbName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strOrderDbName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } if (String.IsNullOrEmpty(strIssueDbName) == false) { if (bRecreate == false) { // 检查cfgdom中是否已经存在同名的期库 if (this.IsOrderDbName(strIssueDbName) == true) { strError = "期库 '" + strIssueDbName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strIssueDbName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } if (String.IsNullOrEmpty(strCommentDbName) == false) { if (bRecreate == false) { // 检查cfgdom中是否已经存在同名的评注库 if (this.IsCommentDbName(strCommentDbName) == true) { strError = "评注库 '" + strCommentDbName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strCommentDbName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } // 开始创建 // 创建书目库 string strTemplateDir = this.DataDir + "\\templates\\" + "biblio_" + strSyntax + "_" + strUsage; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; // 创建实体库 if (String.IsNullOrEmpty(strEntityDbName) == false) { strTemplateDir = this.DataDir + "\\templates\\" + "item"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strEntityDbName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strEntityDbName); bDbChanged = true; } // 创建订购库 if (String.IsNullOrEmpty(strOrderDbName) == false) { strTemplateDir = this.DataDir + "\\templates\\" + "order"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strOrderDbName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strOrderDbName); bDbChanged = true; } // 创建期库 if (String.IsNullOrEmpty(strIssueDbName) == false) { strTemplateDir = this.DataDir + "\\templates\\" + "issue"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strIssueDbName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strIssueDbName); bDbChanged = true; } // 创建评注库 if (String.IsNullOrEmpty(strCommentDbName) == false) { strTemplateDir = this.DataDir + "\\templates\\" + "comment"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strCommentDbName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strCommentDbName); bDbChanged = true; } // 在CfgDom中增加相关的配置信息 XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup"); if (root == null) { root = this.LibraryCfgDom.CreateElement("itemdbgroup"); this.LibraryCfgDom.DocumentElement.AppendChild(root); } XmlNode nodeNewDatabase = null; if (bRecreate == false) { nodeNewDatabase = this.LibraryCfgDom.CreateElement("database"); root.AppendChild(nodeNewDatabase); } else { nodeNewDatabase = exist_database_node; } DomUtil.SetAttr(nodeNewDatabase, "name", strEntityDbName); DomUtil.SetAttr(nodeNewDatabase, "biblioDbName", strName); if (String.IsNullOrEmpty(strOrderDbName) == false) { DomUtil.SetAttr(nodeNewDatabase, "orderDbName", strOrderDbName); } if (String.IsNullOrEmpty(strIssueDbName) == false) { DomUtil.SetAttr(nodeNewDatabase, "issueDbName", strIssueDbName); } if (String.IsNullOrEmpty(strCommentDbName) == false) { DomUtil.SetAttr(nodeNewDatabase, "commentDbName", strCommentDbName); } DomUtil.SetAttr(nodeNewDatabase, "syntax", strSyntax); // 2009/10/23 DomUtil.SetAttr(nodeNewDatabase, "role", strRole); DomUtil.SetAttr(nodeNewDatabase, "inCirculation", strInCirculation); // 2012/4/30 if (string.IsNullOrEmpty(strUnionCatalogStyle) == false) DomUtil.SetAttr(nodeNewDatabase, "unionCatalogStyle", strUnionCatalogStyle); if (string.IsNullOrEmpty(strReplication) == false) DomUtil.SetAttr(nodeNewDatabase, "replication", strReplication); // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); goto ERROR1; } this.Changed = true; this.ActivateManagerThread(); created_dbnames.Clear(); continue; } // end of type biblio else if (strType == "entity") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建实体库"; return -1; } // TODO: 增加recreate能力 // 单独创建实体库 string strBiblioDbName = DomUtil.GetAttr(node, "biblioDbName"); if (String.IsNullOrEmpty(strBiblioDbName) == true) { strError = "请求创建实体库的<database>元素中,应包含biblioDbName属性"; goto ERROR1; } // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@biblioDbName='" + strBiblioDbName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strBiblioDbName + "' 的书目库(biblioDbName属性)相关<database>元素没有找到,无法在其下创建实体库 " + strName; goto ERROR1; } string strOldEntityDbName = DomUtil.GetAttr(nodeDatabase, "name"); if (strOldEntityDbName == strName) { strError = "从属于书目库 '" + strBiblioDbName + "' 的实体库 '" + strName + "' 定义已经存在,不能重复创建"; goto ERROR1; } if (String.IsNullOrEmpty(strOldEntityDbName) == false) { strError = "要创建从属于书目库 '" + strBiblioDbName + "' 的新实体库 '" + strName + "',必须先删除已经存在的实体库 '" + strOldEntityDbName + "'"; goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + "item"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; DomUtil.SetAttr(nodeDatabase, "name", strName); // 2008/12/4 // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); goto ERROR1; } this.Changed = true; } else if (strType == "order") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建订购库"; return -1; } // TODO: 增加recreate能力 // 单独创建订购库 string strBiblioDbName = DomUtil.GetAttr(node, "biblioDbName"); if (String.IsNullOrEmpty(strBiblioDbName) == true) { strError = "创建订购库的<database>元素中,应包含biblioDbName属性"; goto ERROR1; } // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@biblioDbName='" + strBiblioDbName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strBiblioDbName + "' 的书目库(biblioDbName属性)相关<database>元素没有找到,无法在其下创建订购库 " + strName; goto ERROR1; } string strOldOrderDbName = DomUtil.GetAttr(nodeDatabase, "orderDbName"); if (strOldOrderDbName == strName) { strError = "从属于书目库 '" + strBiblioDbName + "' 的订购库 '" + strName + "' 定义已经存在,不能重复创建"; goto ERROR1; } if (String.IsNullOrEmpty(strOldOrderDbName) == false) { strError = "要创建从属于书目库 '" + strBiblioDbName + "' 的新订购库 '" + strName + "',必须先删除已经存在的订购库 '" + strOldOrderDbName + "'"; goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + "order"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; DomUtil.SetAttr(nodeDatabase, "orderDbName", strName); // 2008/12/4 // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); goto ERROR1; } this.Changed = true; } else if (strType == "issue") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建期库"; return -1; } // TODO: 增加recreate能力 // 单独创建期库 string strBiblioDbName = DomUtil.GetAttr(node, "biblioDbName"); if (String.IsNullOrEmpty(strBiblioDbName) == true) { strError = "创建期库的<database>元素中,应包含biblioDbName属性"; goto ERROR1; } // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@biblioDbName='" + strBiblioDbName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strBiblioDbName + "' 的书目库(biblioDbName属性)相关<database>元素没有找到,无法在其下创建期库 " + strName; goto ERROR1; } string strOldIssueDbName = DomUtil.GetAttr(nodeDatabase, "issueDbName"); if (strOldIssueDbName == strName) { strError = "从属于书目库 '"+strBiblioDbName+"' 的期库 '" + strName + "' 定义已经存在,不能重复创建"; goto ERROR1; } if (String.IsNullOrEmpty(strOldIssueDbName) == false) { strError = "要创建从属于书目库 '" + strBiblioDbName + "' 的新期库 '" + strName + "',必须先删除已经存在的期库 '" +strOldIssueDbName+"'"; goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + "issue"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; DomUtil.SetAttr(nodeDatabase, "issueDbName", strName); // 2008/12/4 // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); goto ERROR1; } this.Changed = true; } else if (strType == "comment") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建评注库"; return -1; } // TODO: 增加recreate能力 // 单独创建评注库 string strBiblioDbName = DomUtil.GetAttr(node, "biblioDbName"); if (String.IsNullOrEmpty(strBiblioDbName) == true) { strError = "创建评注库的<database>元素中,应包含biblioDbName属性"; goto ERROR1; } // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@biblioDbName='" + strBiblioDbName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strBiblioDbName + "' 的书目库(biblioDbName属性)相关<database>元素没有找到,无法在其下创建评注库 " + strName; goto ERROR1; } string strOldCommentDbName = DomUtil.GetAttr(nodeDatabase, "commentDbName"); if (strOldCommentDbName == strName) { strError = "从属于书目库 '" + strBiblioDbName + "' 的评注库 '" + strName + "' 定义已经存在,不能重复创建"; goto ERROR1; } if (String.IsNullOrEmpty(strOldCommentDbName) == false) { strError = "要创建从属于书目库 '" + strBiblioDbName + "' 的新评注库 '" + strName + "',必须先删除已经存在的评注库 '" + strOldCommentDbName + "'"; goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + "comment"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; DomUtil.SetAttr(nodeDatabase, "commentDbName", strName); // 2008/12/4 // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); goto ERROR1; } this.Changed = true; } else if (strType == "reader") { // 创建读者库 // 2009/11/13 XmlNode exist_database_node = this.LibraryCfgDom.DocumentElement.SelectSingleNode("readerdbgroup/database[@name='" + strName + "']"); if (bRecreate == true && exist_database_node == null) { strError = "library.xml中并不存在读者库 '" + strName + "' 的定义,无法进行重新创建"; goto ERROR1; } if (bRecreate == false) { // 检查cfgdom中是否已经存在同名的读者库 if (this.IsReaderDbName(strName) == true) { strError = "读者库 '" + strName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } else { if (exist_database_node != null) { string strExistLibraryCode = DomUtil.GetAttr(exist_database_node, "libraryCode"); // 2012/9/9 // 分馆用户只允许修改馆代码属于管辖分馆的读者库 if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { if (string.IsNullOrEmpty(strExistLibraryCode) == true || StringUtil.IsInList(strExistLibraryCode, strLibraryCodeList) == false) { strError = "重新创建读者库 '"+strName+"' 被拒绝。当前用户只能重新创建图书馆代码完全完全属于 '" + strLibraryCodeList + "' 范围的读者库"; goto ERROR1; } } } } string strLibraryCode = DomUtil.GetAttr(node, "libraryCode"); // 2012/9/9 // 分馆用户只允许处理馆代码为特定范围的读者库 if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { if (string.IsNullOrEmpty(strLibraryCode) == true || IsListInList(strLibraryCode, strLibraryCodeList) == false) { strError = "当前用户只能创建馆代码完全属于 '" + strLibraryCodeList + "' 范围内的读者库"; return -1; } } // 检查dp2kernel中是否有和读者库同名的数据库存在 { // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + "reader"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; string strInCirculation = DomUtil.GetAttr(node, "inCirculation"); if (String.IsNullOrEmpty(strInCirculation) == true) strInCirculation = "true"; // 缺省为true // 检查一个单独的图书馆代码是否格式正确 // 要求不能为 '*',不能包含逗号 // return: // -1 校验函数本身出错了 // 0 校验正确 // 1 校验发现问题。strError中有描述 nRet = VerifySingleLibraryCode(strLibraryCode, out strError); if (nRet != 0) { strError = "图书馆代码 '" + strLibraryCode + "' 格式错误: " + strError; goto ERROR1; } // 在CfgDom中增加相关的配置信息 XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("readerdbgroup"); if (root == null) { root = this.LibraryCfgDom.CreateElement("readerdbgroup"); this.LibraryCfgDom.DocumentElement.AppendChild(root); } XmlNode nodeNewDatabase = null; if (bRecreate == false) { nodeNewDatabase = this.LibraryCfgDom.CreateElement("database"); root.AppendChild(nodeNewDatabase); } else { nodeNewDatabase = exist_database_node; } DomUtil.SetAttr(nodeNewDatabase, "name", strName); DomUtil.SetAttr(nodeNewDatabase, "inCirculation", strInCirculation); DomUtil.SetAttr(nodeNewDatabase, "libraryCode", strLibraryCode); // 2012/9/7 // <readerdbgroup>内容更新,刷新配套的内存结构 this.LoadReaderDbGroupParam(this.LibraryCfgDom); this.Changed = true; } else if (strType == "publisher" || strType == "zhongcihao" || strType == "dictionary" || strType == "inventory") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建出版者库、种次号库、字典库和盘点库"; return -1; } // 看看同名的 publisher/zhongcihao/dictionary/inventory 数据库是否已经存在? XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("utilDb/database[@name='" + strName + "']"); if (bRecreate == false) { if (nodeDatabase != null) { strError = strType + "库 '" + strName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } else { if (nodeDatabase == null) { strError = strType + "库 '" + strName + "' 的定义并不存在,无法进行重复创建"; goto ERROR1; } } // TODO: 是否限定publisher库只能创建一个? // 而zhongcihao库显然是可以创建多个的 // 检查dp2kernel中是否有和 publisher/zhongcihao/dictionary/inventory 库同名的数据库存在 { // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + strType; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; // 2012/12/12 // 在CfgDom中增加相关的配置信息 XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("utilDb"); if (root == null) { root = this.LibraryCfgDom.CreateElement("utilDb"); this.LibraryCfgDom.DocumentElement.AppendChild(root); } XmlNode nodeNewDatabase = null; if (bRecreate == false) { nodeNewDatabase = this.LibraryCfgDom.CreateElement("database"); root.AppendChild(nodeNewDatabase); } else { nodeNewDatabase = nodeDatabase; } DomUtil.SetAttr(nodeNewDatabase, "name", strName); DomUtil.SetAttr(nodeNewDatabase, "type", strType); this.Changed = true; } else if (strType == "arrived") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建预约到书库"; return -1; } // 看看同名的 arrived 数据库是否已经存在? if (bRecreate == false) { if (this.ArrivedDbName == strName) { strError = "预约到书库 '" + strName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } if (String.IsNullOrEmpty(this.ArrivedDbName) == false) { if (bRecreate == true) { if (this.ArrivedDbName != strName) { strError = "已经存在一个预约到书库 '" + this.ArrivedDbName + "' 定义,和您请求重新创建的预约到书库 '" + strName + "' 名字不同。无法直接进行重新创建。请先删除已存在的数据库再进行创建"; goto ERROR1; } } else { strError = "要创建新的预约到书库 '" + strName + "',必须先删除已经存在的预约到书库 '" + this.ArrivedDbName + "'"; goto ERROR1; } } // 检查dp2kernel中是否有和arrived库同名的数据库存在 { // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + "arrived"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; // 2012/12/12 // 在CfgDom中增加相关的配置信息 this.ArrivedDbName = strName; this.Changed = true; } else if (strType == "amerce") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建违约金库"; return -1; } // 看看同名的amerce数据库是否已经存在? if (bRecreate == false) { if (this.AmerceDbName == strName) { strError = "违约金库 '" + strName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } if (String.IsNullOrEmpty(this.AmerceDbName) == false) { if (bRecreate == true) { if (this.AmerceDbName != strName) { strError = "已经存在一个违约金库 '" + this.AmerceDbName + "' 定义,和您请求重新创建的违约金库 '" + strName + "' 名字不同。无法直接进行重新创建。请先删除已存在的数据库再进行创建"; goto ERROR1; } } else { strError = "要创建新的违约金库 '" + strName + "',必须先删除已经存在的违约金库 '" + this.AmerceDbName + "'"; goto ERROR1; } } // 检查dp2kernel中是否有和amerce库同名的数据库存在 { // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + "amerce"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; // 2012/12/12 // 在CfgDom中增加相关的配置信息 this.AmerceDbName = strName; this.Changed = true; } else if (strType == "message") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建消息库"; return -1; } // 看看同名的message数据库是否已经存在? if (bRecreate == false) { if (this.MessageDbName == strName) { strError = "消息库 '" + strName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } if (String.IsNullOrEmpty(this.MessageDbName) == false) { if (bRecreate == true) { if (this.MessageDbName != strName) { strError = "已经存在一个消息库 '" + this.MessageDbName + "' 定义,和您请求重新创建的消息库 '" + strName + "' 名字不同。无法直接进行重新创建。请先删除已存在的数据库再进行创建"; goto ERROR1; } } else { strError = "要创建新的消息库 '" + strName + "',必须先删除已经存在的消息库 '" + this.MessageDbName + "'"; goto ERROR1; } } // 检查dp2kernel中是否有和message库同名的数据库存在 { // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + "message"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; // 2012/12/12 // 在CfgDom中增加相关的配置信息 this.MessageDbName = strName; this.Changed = true; } else if (strType == "invoice") { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许创建或重新创建发票库"; return -1; } // 看看同名的invoice数据库是否已经存在? if (bRecreate == false) { if (this.InvoiceDbName == strName) { strError = "发票库 '" + strName + "' 的定义已经存在,不能重复创建"; goto ERROR1; } } if (String.IsNullOrEmpty(this.InvoiceDbName) == false) { if (bRecreate == true) { if (this.InvoiceDbName != strName) { strError = "已经存在一个发票库 '" + this.InvoiceDbName + "' 定义,和您请求重新创建的发票库 '" + strName + "' 名字不同。无法直接进行重新创建。请先删除已存在的数据库再进行创建"; goto ERROR1; } } else { strError = "要创建新的发票库 '" + strName + "',必须先删除已经存在的发票库 '" + this.InvoiceDbName + "'"; goto ERROR1; } } // 检查dp2kernel中是否有和invoice库同名的数据库存在 { // 数据库是否已经存在? // return: // -1 error // 0 not exist // 1 exist // 2 其他类型的同名对象已经存在 nRet = IsDatabaseExist( channel, strName, out strError); if (nRet == -1) goto ERROR1; if (nRet >= 1) goto ERROR1; } string strTemplateDir = this.DataDir + "\\templates\\" + "invoice"; // 根据预先的定义,创建一个数据库 nRet = CreateDatabase(channel, strTemplateDir, strName, out strError); if (nRet == -1) goto ERROR1; created_dbnames.Add(strName); bDbChanged = true; // 2012/12/12 // 在CfgDom中增加相关的配置信息 this.InvoiceDbName = strName; this.Changed = true; } else { strError = "未知的数据库类型 '" + strType + "'"; goto ERROR1; } if (this.Changed == true) this.ActivateManagerThread(); created_dbnames.Clear(); } Debug.Assert(created_dbnames.Count == 0, ""); if (bDbChanged == true) { nRet = InitialKdbs( Channels, out strError); if (nRet == -1) return -1; // 重新初始化虚拟库定义 this.vdbs = null; nRet = this.InitialVdbs(Channels, out strError); if (nRet == -1) return -1; } return 0; ERROR1: List<string> error_deleting_dbnames = new List<string>(); // 将本次已经创建的数据库在返回前删除掉 for (int i = 0; i < created_dbnames.Count; i++) { string strDbName = created_dbnames[i]; string strError_1 = ""; long lRet = channel.DoDeleteDB(strDbName, out strError_1); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) continue; if (lRet == -1) error_deleting_dbnames.Add(strDbName + "[错误:"+strError_1+"]"); } if (error_deleting_dbnames.Count > 0) { strError = strError + ";\r\n并在删除刚创建的数据库时发生错误,下列数据库未被删除:" + StringUtil.MakePathList(error_deleting_dbnames); return -1; } return -1; }
// 修改数据库 int ChangeDatabase( RmsChannelCollection Channels, string strLibraryCodeList, string strDatabaseNames, string strDatabaseInfo, out string strOutputInfo, out string strError) { strOutputInfo = ""; strError = ""; int nRet = 0; // long lRet = 0; bool bDbNameChanged = false; XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strDatabaseInfo); } catch (Exception ex) { strError = "strDatabaseInfo内容装入XMLDOM时出错: " + ex.Message; return -1; } // 核对strDatabaseNames中包含的数据库名数目是否和dom中的<database>元素数相等 string[] names = strDatabaseNames.Split(new char[] {','}); XmlNodeList nodes = dom.DocumentElement.SelectNodes("database"); if (names.Length != nodes.Count) { strError = "strDatabaseNames参数中包含的数据库名个数 "+names.Length.ToString()+" 和strDatabaseInfo参数中包含的<database>元素数 "+nodes.Count.ToString()+" 不等"; return -1; } RmsChannel channel = Channels.GetChannel(this.WsUrl); for (int i = 0; i < names.Length; i++) { string strName = names[i].Trim(); if (String.IsNullOrEmpty(strName) == true) { strError = "strDatabaseNames参数中不能包含空的名字"; return -1; } // 来自strDatabaseInfo XmlElement nodeNewDatabase = nodes[i] as XmlElement; // 修改书目库名、或者书目库从属的其他数据库名 if (this.IsBiblioDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@biblioDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的书目库(biblioDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改书目库定义"; return -1; } /* * <database>元素中的name/entityDbName/orderDbName/issueDbName * 传递了改名请求。如果属性值为空,不表明要删除数据库,而是该属性无效。 * 实际上这里不响应删除数据库的动作,只能改名 * 将来可以改造为响应删除数据库的请求,那么,只要属性具备,就有请求。如果不想请求,则不要包含那个属性 * */ { // 书目库名 string strOldBiblioDbName = strName; // 来自strDatabaseInfo string strNewBiblioDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); // 如果strNewBiblioDbName为空,表示不想改变名字 if (String.IsNullOrEmpty(strNewBiblioDbName) == false && strOldBiblioDbName != strNewBiblioDbName) { if (String.IsNullOrEmpty(strOldBiblioDbName) == true && String.IsNullOrEmpty(strNewBiblioDbName) == false) { strError = "要创建书目库 '" + strNewBiblioDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldBiblioDbName, strNewBiblioDbName, () => { DomUtil.SetAttr(nodeDatabase, "biblioDbName", strNewBiblioDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "biblioDbName", strNewBiblioDbName); this.Changed = true; #endif } } { // 实体库名 string strOldEntityDbName = DomUtil.GetAttr(nodeDatabase, "name"); // 来自strDatabaseInfo string strNewEntityDbName = DomUtil.GetAttr(nodeNewDatabase, "entityDbName"); if (String.IsNullOrEmpty(strNewEntityDbName) == false && strOldEntityDbName != strNewEntityDbName) { if (String.IsNullOrEmpty(strOldEntityDbName) == true && String.IsNullOrEmpty(strNewEntityDbName) == false) { strError = "要创建实体库 '" + strNewEntityDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldEntityDbName, strNewEntityDbName, () => { DomUtil.SetAttr(nodeDatabase, "name", strNewEntityDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "name", strNewEntityDbName); this.Changed = true; #endif } } { // 订购库名 string strOldOrderDbName = DomUtil.GetAttr(nodeDatabase, "orderDbName"); // 来自strDatabaseInfo string strNewOrderDbName = DomUtil.GetAttr(nodeNewDatabase, "orderDbName"); if (String.IsNullOrEmpty(strNewOrderDbName) == false && strOldOrderDbName != strNewOrderDbName) { if (String.IsNullOrEmpty(strOldOrderDbName) == true && String.IsNullOrEmpty(strNewOrderDbName) == false) { strError = "要创建订购库 '" + strNewOrderDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldOrderDbName, strNewOrderDbName, () => { DomUtil.SetAttr(nodeDatabase, "orderDbName", strNewOrderDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "orderDbName", strNewOrderDbName); this.Changed = true; #endif } } { // 期库名 string strOldIssueDbName = DomUtil.GetAttr(nodeDatabase, "issueDbName"); // 来自strDatabaseInfo string strNewIssueDbName = DomUtil.GetAttr(nodeNewDatabase, "issueDbName"); if (String.IsNullOrEmpty(strNewIssueDbName) == false && strOldIssueDbName != strNewIssueDbName) { if (String.IsNullOrEmpty(strOldIssueDbName) == true && String.IsNullOrEmpty(strNewIssueDbName) == false) { strError = "要创建期库 '" + strNewIssueDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldIssueDbName, strNewIssueDbName, () => { DomUtil.SetAttr(nodeDatabase, "issueDbName", strNewIssueDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "issueDbName", strNewIssueDbName); this.Changed = true; #endif } } { // 评注库名 string strOldCommentDbName = DomUtil.GetAttr(nodeDatabase, "commentDbName"); // 来自strDatabaseInfo string strNewCommentDbName = DomUtil.GetAttr(nodeNewDatabase, "commentDbName"); if (String.IsNullOrEmpty(strNewCommentDbName) == false && strOldCommentDbName != strNewCommentDbName) { if (String.IsNullOrEmpty(strOldCommentDbName) == true && String.IsNullOrEmpty(strNewCommentDbName) == false) { strError = "要创建评注库 '" + strNewCommentDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldCommentDbName, strNewCommentDbName, () => { DomUtil.SetAttr(nodeDatabase, "commentDbName", strNewCommentDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "commentDbName", strNewCommentDbName); this.Changed = true; #endif } } // 是否参与流通 if (DomUtil.HasAttr(nodeNewDatabase, "inCirculation") == true) { string strOldInCirculation = DomUtil.GetAttr(nodeDatabase, "inCirculation"); if (String.IsNullOrEmpty(strOldInCirculation) == true) strOldInCirculation = "true"; string strNewInCirculation = DomUtil.GetAttr(nodeNewDatabase, "inCirculation"); if (String.IsNullOrEmpty(strNewInCirculation) == true) strNewInCirculation = "true"; if (strOldInCirculation != strNewInCirculation) { DomUtil.SetAttr(nodeDatabase, "inCirculation", strNewInCirculation); this.Changed = true; } } // 角色 // TODO: 是否要进行检查? if (DomUtil.HasAttr(nodeNewDatabase, "role") == true) { string strOldRole = DomUtil.GetAttr(nodeDatabase, "role"); string strNewRole = DomUtil.GetAttr(nodeNewDatabase, "role"); if (strOldRole != strNewRole) { DomUtil.SetAttr(nodeDatabase, "role", strNewRole); this.Changed = true; } } // 2012/4/30 // 联合编目特性 if (DomUtil.HasAttr(nodeNewDatabase, "unionCatalogStyle") == true) { string strOldUnionCatalogStyle = DomUtil.GetAttr(nodeDatabase, "unionCatalogStyle"); string strNewUnionCatalogStyle = DomUtil.GetAttr(nodeNewDatabase, "unionCatalogStyle"); if (strOldUnionCatalogStyle != strNewUnionCatalogStyle) { DomUtil.SetAttr(nodeDatabase, "unionCatalogStyle", strNewUnionCatalogStyle); this.Changed = true; } } // 复制 if (DomUtil.HasAttr(nodeNewDatabase, "replication") == true) { string strOldReplication = DomUtil.GetAttr(nodeDatabase, "replication"); string strNewReplication = DomUtil.GetAttr(nodeNewDatabase, "replication"); if (strOldReplication != strNewReplication) { DomUtil.SetAttr(nodeDatabase, "replication", strNewReplication); this.Changed = true; } } // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } this.Changed = true; continue; } // end of if 书目库名 // 单独修改实体库名 // 能修改是否参与流通 if (this.IsItemDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的实体库(name属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改实体库定义"; return -1; } // 实体库名 string strOldEntityDbName = DomUtil.GetAttr(nodeDatabase, "name"); // 来自strDatabaseInfo string strNewEntityDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); if (strOldEntityDbName != strNewEntityDbName) { if (String.IsNullOrEmpty(strOldEntityDbName) == true && String.IsNullOrEmpty(strNewEntityDbName) == false) { strError = "要创建实体库 '" + strNewEntityDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldEntityDbName) == false && String.IsNullOrEmpty(strNewEntityDbName) == true) { strError = "要删除实体库 '" + strNewEntityDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldEntityDbName, strNewEntityDbName, () => { DomUtil.SetAttr(nodeDatabase, "name", strNewEntityDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "name", strNewEntityDbName); this.Changed = true; #endif } // 是否参与流通 { string strOldInCirculation = DomUtil.GetAttr(nodeDatabase, "inCirculation"); if (String.IsNullOrEmpty(strOldInCirculation) == true) strOldInCirculation = "true"; string strNewInCirculation = DomUtil.GetAttr(nodeNewDatabase, "inCirculation"); if (String.IsNullOrEmpty(strNewInCirculation) == true) strNewInCirculation = "true"; if (strOldInCirculation != strNewInCirculation) { DomUtil.SetAttr(nodeDatabase, "inCirculation", strNewInCirculation); this.Changed = true; } } // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } this.Changed = true; continue; } // 单独修改订购库名 if (this.IsOrderDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@orderDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的订购库(orderDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改订购库定义"; return -1; } // 来自LibraryCfgDom string strOldOrderDbName = DomUtil.GetAttr(nodeDatabase, "orderDbName"); // 来自strDatabaseInfo string strNewOrderDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); if (strOldOrderDbName != strNewOrderDbName) { if (String.IsNullOrEmpty(strOldOrderDbName) == true && String.IsNullOrEmpty(strNewOrderDbName) == false) { strError = "要创建订购库 '" + strNewOrderDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldOrderDbName) == false && String.IsNullOrEmpty(strNewOrderDbName) == true) { strError = "要删除订购库 '" + strNewOrderDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldOrderDbName, strNewOrderDbName, () => { DomUtil.SetAttr(nodeDatabase, "orderDbName", strNewOrderDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "orderDbName", strNewOrderDbName); this.Changed = true; #endif } // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } this.Changed = true; continue; } // 单独修改期库名 if (this.IsIssueDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@issueDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的期库(issueDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改期库定义"; return -1; } // 来自LibraryCfgDom string strOldIssueDbName = DomUtil.GetAttr(nodeDatabase, "issueDbName"); // 来自strDatabaseInfo string strNewIssueDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); // 2012/4/30 changed if (strOldIssueDbName != strNewIssueDbName) { if (String.IsNullOrEmpty(strOldIssueDbName) == true && String.IsNullOrEmpty(strNewIssueDbName) == false) { strError = "要创建期库 '" + strNewIssueDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldIssueDbName) == false && String.IsNullOrEmpty(strNewIssueDbName) == true) { strError = "要删除期库 '" + strNewIssueDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldIssueDbName, strNewIssueDbName, () => { DomUtil.SetAttr(nodeDatabase, "issueDbName", strNewIssueDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "issueDbName", strNewIssueDbName); this.Changed = true; #endif } // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } this.Changed = true; continue; } // 单独修改评注库名 if (this.IsCommentDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@commentDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的评注库(commentDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改评注库定义"; return -1; } // 来自LibraryCfgDom string strOldCommentDbName = DomUtil.GetAttr(nodeDatabase, "commentDbName"); // 来自strDatabaseInfo string strNewCommentDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); // 2012/4/30 changed if (strOldCommentDbName != strNewCommentDbName) { if (String.IsNullOrEmpty(strOldCommentDbName) == true && String.IsNullOrEmpty(strNewCommentDbName) == false) { strError = "要创建评注库 '" + strNewCommentDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldCommentDbName) == false && String.IsNullOrEmpty(strNewCommentDbName) == true) { strError = "要删除评注库 '" + strNewCommentDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldCommentDbName, strNewCommentDbName, () => { DomUtil.SetAttr(nodeDatabase, "commentDbName", strNewCommentDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "commentDbName", strNewCommentDbName); this.Changed = true; #endif } // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } this.Changed = true; continue; } // 修改读者库名 if (this.IsReaderDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("readerdbgroup/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的读者库(name属性)相关<database>元素没有找到"; return -1; } // 2012/9/9 // 分馆用户只允许修改属于管辖分馆的读者库 if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { string strExistLibraryCode = DomUtil.GetAttr(nodeDatabase, "libraryCode"); if (string.IsNullOrEmpty(strExistLibraryCode) == true || StringUtil.IsInList(strExistLibraryCode, strLibraryCodeList) == false) { strError = "修改读者库 '" + strName + "' 定义被拒绝。当前用户只能修改图书馆代码完全属于 '" + strLibraryCodeList + "' 范围的读者库"; return -1; } } // 来自LibraryCfgDom string strOldReaderDbName = DomUtil.GetAttr(nodeDatabase, "name"); // 来自strDatabaseInfo string strNewReaderDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); if (strOldReaderDbName != strNewReaderDbName) { if (String.IsNullOrEmpty(strOldReaderDbName) == true && String.IsNullOrEmpty(strNewReaderDbName) == false) { strError = "要创建读者库 '" + strNewReaderDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldReaderDbName) == false && String.IsNullOrEmpty(strNewReaderDbName) == true) { strError = "要删除读者库 '" + strNewReaderDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldReaderDbName, strNewReaderDbName, () => { DomUtil.SetAttr(nodeDatabase, "name", strNewReaderDbName); bDbNameChanged = true; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "name", strNewReaderDbName); this.Changed = true; #endif } // 是否参与流通 // 只有当提交的 XML 片断中具有 inCirculation 属性的时候,才会发生修改 if (nodeNewDatabase.GetAttributeNode("inCirculation") != null) { // 来自LibraryCfgDom string strOldInCirculation = DomUtil.GetAttr(nodeDatabase, "inCirculation"); if (String.IsNullOrEmpty(strOldInCirculation) == true) strOldInCirculation = "true"; // 来自strDatabaseInfo string strNewInCirculation = DomUtil.GetAttr(nodeNewDatabase, "inCirculation"); if (String.IsNullOrEmpty(strNewInCirculation) == true) strNewInCirculation = "true"; if (strOldInCirculation != strNewInCirculation) { DomUtil.SetAttr(nodeDatabase, "inCirculation", strNewInCirculation); this.Changed = true; } } // 2012/9/7 // 图书馆代码 // 只有当提交的 XML 片断中具有 libraryCode 属性的时候,才会发生修改 if (nodeNewDatabase.GetAttributeNode("libraryCode") != null) { // 来自LibraryCfgDom string strOldLibraryCode = DomUtil.GetAttr(nodeDatabase, "libraryCode"); // 来自strDatabaseInfo string strNewLibraryCode = DomUtil.GetAttr(nodeNewDatabase, "libraryCode"); if (strOldLibraryCode != strNewLibraryCode) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { if (string.IsNullOrEmpty(strNewLibraryCode) == true || StringUtil.IsInList(strNewLibraryCode, strLibraryCodeList) == false) { strError = "修改读者库 '" + strName + "' 定义被拒绝。修改后的新图书馆代码必须完全属于 '" + strLibraryCodeList + "' 范围"; return -1; } } // 检查一个单独的图书馆代码是否格式正确 // 要求不能为 '*',不能包含逗号 // return: // -1 校验函数本身出错了 // 0 校验正确 // 1 校验发现问题。strError中有描述 nRet = VerifySingleLibraryCode(strNewLibraryCode, out strError); if (nRet != 0) { strError = "图书馆代码 '" + strNewLibraryCode + "' 格式错误: " + strError; goto ERROR1; } DomUtil.SetAttr(nodeDatabase, "libraryCode", strNewLibraryCode); this.Changed = true; } } // <readerdbgroup>内容更新,刷新配套的内存结构 this.LoadReaderDbGroupParam(this.LibraryCfgDom); this.Changed = true; continue; } // 修改预约到书库名 if (this.ArrivedDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改预约到书库定义"; return -1; } string strOldArrivedDbName = this.ArrivedDbName; // 来自strDatabaseInfo string strNewArrivedDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); if (strOldArrivedDbName != strNewArrivedDbName) { if (String.IsNullOrEmpty(strOldArrivedDbName) == true && String.IsNullOrEmpty(strNewArrivedDbName) == false) { strError = "要创建预约到书库 '" + strNewArrivedDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldArrivedDbName) == false && String.IsNullOrEmpty(strNewArrivedDbName) == true) { strError = "要删除预约到书库 '" + strNewArrivedDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldArrivedDbName, strNewArrivedDbName, () => { this.ArrivedDbName = strNewArrivedDbName; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO this.Changed = true; this.ArrivedDbName = strNewArrivedDbName; #endif } continue; } // 修改违约金库名 if (this.AmerceDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改违约金库定义"; return -1; } string strOldAmerceDbName = this.AmerceDbName; // 来自strDatabaseInfo string strNewAmerceDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); if (strOldAmerceDbName != strNewAmerceDbName) { if (String.IsNullOrEmpty(strOldAmerceDbName) == true && String.IsNullOrEmpty(strNewAmerceDbName) == false) { strError = "要创建违约金库 '" + strNewAmerceDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldAmerceDbName) == false && String.IsNullOrEmpty(strNewAmerceDbName) == true) { strError = "要删除违约金库 '" + strNewAmerceDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldAmerceDbName, strNewAmerceDbName, () => { this.AmerceDbName = strNewAmerceDbName; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO this.Changed = true; this.AmerceDbName = strNewAmerceDbName; #endif } continue; } // 修改发票库名 if (this.InvoiceDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改发票库定义"; return -1; } string strOldInvoiceDbName = this.InvoiceDbName; // 来自strDatabaseInfo string strNewInvoiceDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); if (strOldInvoiceDbName != strNewInvoiceDbName) { if (String.IsNullOrEmpty(strOldInvoiceDbName) == true && String.IsNullOrEmpty(strNewInvoiceDbName) == false) { strError = "要创建发票库 '" + strNewInvoiceDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldInvoiceDbName) == false && String.IsNullOrEmpty(strNewInvoiceDbName) == true) { strError = "要删除发票库 '" + strNewInvoiceDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldInvoiceDbName, strNewInvoiceDbName, () => { this.InvoiceDbName = strNewInvoiceDbName; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO this.Changed = true; this.InvoiceDbName = strNewInvoiceDbName; #endif } continue; } // 修改消息库名 if (this.MessageDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改预约消息库定义"; return -1; } string strOldMessageDbName = this.MessageDbName; // 来自strDatabaseInfo string strNewMessageDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); if (strOldMessageDbName != strNewMessageDbName) { if (String.IsNullOrEmpty(strOldMessageDbName) == true && String.IsNullOrEmpty(strNewMessageDbName) == false) { strError = "要创建消息库 '" + strNewMessageDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldMessageDbName) == false && String.IsNullOrEmpty(strNewMessageDbName) == true) { strError = "要删除消息库 '" + strNewMessageDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldMessageDbName, strNewMessageDbName, () => { this.MessageDbName = strNewMessageDbName; this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO this.Changed = true; this.MessageDbName = strNewMessageDbName; #endif } continue; } // 修改实用库名 if (IsUtilDbName(strName) == true) { XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("utilDb/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "不存在name属性值为 '"+strName+"' 的<utilDb/database>的元素"; goto ERROR1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许修改实用库定义"; return -1; } string strOldUtilDbName = strName; // 来自strDatabaseInfo string strNewUtilDbName = DomUtil.GetAttr(nodeNewDatabase, "name"); if (strOldUtilDbName != strNewUtilDbName) { if (String.IsNullOrEmpty(strOldUtilDbName) == true && String.IsNullOrEmpty(strNewUtilDbName) == false) { strError = "要创建实用库 '" + strNewUtilDbName + "',请使用create功能,而不能使用change功能"; goto ERROR1; } if (String.IsNullOrEmpty(strOldUtilDbName) == false && String.IsNullOrEmpty(strNewUtilDbName) == true) { strError = "要删除实用库 '" + strNewUtilDbName + "',请使用delete功能,而不能使用change功能"; goto ERROR1; } nRet = ChangeDbName( channel, strOldUtilDbName, strNewUtilDbName, () => { DomUtil.SetAttr(nodeDatabase, "name", strNewUtilDbName); this.Changed = true; }, out strError); if (nRet == -1) goto ERROR1; #if NO this.Changed = true; DomUtil.SetAttr(nodeDatabase, "name", strNewUtilDbName); #endif } string strOldType = DomUtil.GetAttr(nodeDatabase, "type"); string strNewType = DomUtil.GetAttr(nodeNewDatabase, "type"); if (strOldType != strNewType) { DomUtil.SetAttr(nodeDatabase, "type", strNewType); this.Changed = true; // TODO: 类型修改后,是否要应用新的模板来修改数据库定义?这是个大问题 } continue; } strError = "数据库名 '" + strName + "' 不属于 dp2library 目前管辖的范围..."; return -1; } if (this.Changed == true) this.ActivateManagerThread(); if (bDbNameChanged == true) { nRet = InitialKdbs( Channels, out strError); if (nRet == -1) return -1; // 重新初始化虚拟库定义 this.vdbs = null; nRet = this.InitialVdbs(Channels, out strError); if (nRet == -1) return -1; } return 0; ERROR1: // 2015/1/29 if (this.Changed == true) this.ActivateManagerThread(); // 2015/1/29 if (bDbNameChanged == true) { { string strError1 = ""; nRet = InitialKdbs( Channels, out strError1); if (nRet == -1) strError += "; 在收尾的时候进行 InitialKdbs() 调用又出错:" + strError1; } { string strError1 = ""; // 重新初始化虚拟库定义 this.vdbs = null; nRet = this.InitialVdbs(Channels, out strError1); if (nRet == -1) strError += "; 在收尾的时候进行 InitialVdbs() 调用又出错:" + strError1; } } return -1; }
// 删除数据库 int DeleteDatabase( RmsChannelCollection Channels, string strLibraryCodeList, string strDatabaseNames, out string strOutputInfo, out string strError) { strOutputInfo = ""; strError = ""; int nRet = 0; // long lRet = 0; bool bDbNameChanged = false; RmsChannel channel = Channels.GetChannel(this.WsUrl); string[] names = strDatabaseNames.Split(new char[] { ',' }); for (int i = 0; i < names.Length; i++) { string strName = names[i].Trim(); if (String.IsNullOrEmpty(strName) == true) continue; // 书目库整体删除,也是可以的 // TODO: 将来可以考虑单独删除书目库而不删除组内相关库 if (this.IsBiblioDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@biblioDbName='"+strName+"']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的书目库(biblioDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除书目库"; return -1; } // 删除书目库 /* lRet = channel.DoDeleteDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除书目库 '" + strName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除书目库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; // 删除实体库 string strEntityDbName = DomUtil.GetAttr(nodeDatabase, "name"); if (String.IsNullOrEmpty(strEntityDbName) == false) { /* lRet = channel.DoDeleteDB(strEntityDbName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除书目库 '" + strName + "' 所从属的实体库 '" + strEntityDbName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strEntityDbName, out strError); if (nRet == -1) { strError = "删除书目库 '" + strName + "' 所从属的实体库 '" + strEntityDbName + "' 时发生错误: " + strError; return -1; } } // 删除订购库 string strOrderDbName = DomUtil.GetAttr(nodeDatabase, "orderDbName"); if (String.IsNullOrEmpty(strOrderDbName) == false) { /* lRet = channel.DoDeleteDB(strOrderDbName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除书目库 '" + strName + "' 所从属的订购库 '" + strOrderDbName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strOrderDbName, out strError); if (nRet == -1) { strError = "删除书目库 '" + strName + "' 所从属的订购库 '" + strOrderDbName + "' 时发生错误: " + strError; return -1; } } // 删除期库 string strIssueDbName = DomUtil.GetAttr(nodeDatabase, "issueDbName"); if (String.IsNullOrEmpty(strIssueDbName) == false) { /* lRet = channel.DoDeleteDB(strIssueDbName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除书目库 '" + strName + "' 所从属的期库 '" + strIssueDbName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strIssueDbName, out strError); if (nRet == -1) { strError = "删除书目库 '" + strName + "' 所从属的期库 '" + strIssueDbName + "' 时发生错误: " + strError; return -1; } } // 删除评注库 string strCommentDbName = DomUtil.GetAttr(nodeDatabase, "commentDbName"); if (String.IsNullOrEmpty(strCommentDbName) == false) { nRet = DeleteDatabase(channel, strCommentDbName, out strError); if (nRet == -1) { strError = "删除书目库 '" + strName + "' 所从属的评注库 '" + strCommentDbName + "' 时发生错误: " + strError; return -1; } } nodeDatabase.ParentNode.RemoveChild(nodeDatabase); // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } /* // 删除一个数据库在OPAC可检索库中的定义 // return: // -1 error // 0 not change // 1 changed nRet = RemoveOpacDatabaseDef( Channels, strName, out strError); if (nRet == -1) { this.Changed = true; this.ActivateMangerThread(); return -1; }*/ this.Changed = true; this.ActivateManagerThread(); continue; } // 单独删除实体库 if (this.IsItemDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的实体库(name属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除实体库"; return -1; } // 删除实体库 /* lRet = channel.DoDeleteDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除实体库 '" + strName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除实体库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "name", null); // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } this.Changed = true; this.ActivateManagerThread(); continue; } // 单独删除订购库 if (this.IsOrderDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@orderDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的订购库(orderDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除订购库"; return -1; } // 删除订购库 /* lRet = channel.DoDeleteDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除订购库 '" + strName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除订购库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "orderDbName", null); // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } this.Changed = true; this.ActivateManagerThread(); continue; } // 单独删除期库 if (this.IsIssueDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@issueDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的期库(issueDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除期库"; return -1; } // 删除期库 /* lRet = channel.DoDeleteDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除期库 '" + strName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除期库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "issueDbName", null); // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } this.Changed = true; this.ActivateManagerThread(); continue; } // 单独删除评注库 if (this.IsCommentDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@commentDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的评注库(commentDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除评注库"; return -1; } nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除评注库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; DomUtil.SetAttr(nodeDatabase, "commentDbName", null); // <itemdbgroup>内容更新,刷新配套的内存结构 nRet = this.LoadItemDbGroupParam(this.LibraryCfgDom, out strError); if (nRet == -1) { this.WriteErrorLog(strError); return -1; } this.Changed = true; this.ActivateManagerThread(); continue; } // 删除读者库 if (this.IsReaderDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("readerdbgroup/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的读者库(name属性)相关<database>元素没有找到"; return -1; } // 2012/9/9 // 分馆用户只允许删除属于管辖分馆的读者库 if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { string strExistLibraryCode = DomUtil.GetAttr(nodeDatabase, "libraryCode"); if (string.IsNullOrEmpty(strExistLibraryCode) == true || StringUtil.IsInList(strExistLibraryCode, strLibraryCodeList) == false) { strError = "删除读者库 '" + strName + "' 被拒绝。当前用户只能删除图书馆代码完全完全属于 '" + strLibraryCodeList + "' 范围的读者库"; return -1; } } // 删除读者库 /* lRet = channel.DoDeleteDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除读者库 '" + strName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除读者库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; nodeDatabase.ParentNode.RemoveChild(nodeDatabase); // <readerdbgroup>内容更新,刷新配套的内存结构 this.LoadReaderDbGroupParam(this.LibraryCfgDom); /* // 删除一个数据库在OPAC可检索库中的定义 // return: // -1 error // 0 not change // 1 changed nRet = RemoveOpacDatabaseDef( Channels, strName, out strError); if (nRet == -1) { this.Changed = true; this.ActivateMangerThread(); return -1; } * */ this.Changed = true; this.ActivateManagerThread(); continue; } // 删除预约到书库 if (this.ArrivedDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除预约到书库"; return -1; } // 删除预约到书库 /* lRet = channel.DoDeleteDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除预约到书库 '" + strName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除预约到书库 '" + strName + "' 时发生错误: " + strError; return -1; } this.ArrivedDbName = ""; /* // 删除一个数据库在OPAC可检索库中的定义 // return: // -1 error // 0 not change // 1 changed nRet = RemoveOpacDatabaseDef( Channels, strName, out strError); if (nRet == -1) { this.Changed = true; this.ActivateMangerThread(); return -1; } * */ this.Changed = true; this.ActivateManagerThread(); continue; } // 删除违约金库 if (this.AmerceDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除违约金库"; return -1; } // 删除违约金库 /* lRet = channel.DoDeleteDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除违约金库 '" + strName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除违约金库 '" + strName + "' 时发生错误: " + strError; return -1; } this.AmerceDbName = ""; /* // 删除一个数据库在OPAC可检索库中的定义 // return: // -1 error // 0 not change // 1 changed nRet = RemoveOpacDatabaseDef( Channels, strName, out strError); if (nRet == -1) { this.Changed = true; this.ActivateMangerThread(); return -1; }*/ this.Changed = true; this.ActivateManagerThread(); continue; } // 删除发票库 if (this.InvoiceDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除发票库"; return -1; } nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除发票库 '" + strName + "' 时发生错误: " + strError; return -1; } this.InvoiceDbName = ""; this.Changed = true; this.ActivateManagerThread(); continue; } // 删除消息库 if (this.MessageDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除消息库"; return -1; } // 删除消息库 /* lRet = channel.DoDeleteDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除消息库 '" + strName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除消息库 '" + strName + "' 时发生错误: " + strError; return -1; } this.MessageDbName = ""; /* // 删除一个数据库在OPAC可检索库中的定义 // return: // -1 error // 0 not change // 1 changed nRet = RemoveOpacDatabaseDef( Channels, strName, out strError); if (nRet == -1) { this.Changed = true; this.ActivateMangerThread(); return -1; } * */ this.Changed = true; this.ActivateManagerThread(); continue; } // 单独删除实用库 if (IsUtilDbName(strName) == true) { XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("utilDb/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "不存在name属性值为 '" + strName + "' 的<utilDb/database>的元素"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许删除实用库"; return -1; } // 删除实用库 /* lRet = channel.DoDeleteDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "删除实用库 '" + strName + "' 时发生错误: " + strError; return -1; } * */ nRet = DeleteDatabase(channel, strName, out strError); if (nRet == -1) { strError = "删除实用库 '" + strName + "' 时发生错误: " + strError; return -1; } nodeDatabase.ParentNode.RemoveChild(nodeDatabase); /* // 删除一个数据库在OPAC可检索库中的定义 // return: // -1 error // 0 not change // 1 changed nRet = RemoveOpacDatabaseDef( Channels, strName, out strError); if (nRet == -1) { this.Changed = true; this.ActivateMangerThread(); return -1; } * */ this.Changed = true; this.ActivateManagerThread(); continue; } strError = "数据库名 '" +strName+ "' 不属于 dp2library 目前管辖的范围..."; return -1; } if (bDbNameChanged == true) { nRet = InitialKdbs( Channels, out strError); if (nRet == -1) return -1; // 重新初始化虚拟库定义 this.vdbs = null; nRet = this.InitialVdbs(Channels, out strError); if (nRet == -1) return -1; } return 0; }
// 重设置代理帐户密码 int ResetManageUserPassword(out string strError) { strError = ""; if (this.textBox_kernelUrl.Text == "") { strError = "尚未指定dp2Kernel服务器URL"; return -1; } if (this.textBox_manageUserName.Text == "") { strError = "尚未指定代理帐户的用户名"; return -1; } if (this.textBox_managePassword.Text != this.textBox_confirmManagePassword.Text) { strError = "代理帐户 密码 和 再次输入密码 不一致。请重新输入。"; return -1; } RmsChannelCollection channels = new RmsChannelCollection(); channels.AskAccountInfo -= new AskAccountInfoEventHandle(channels_AskAccountInfo); channels.AskAccountInfo += new AskAccountInfoEventHandle(channels_AskAccountInfo); RmsChannel channel = channels.GetChannel(this.textBox_kernelUrl.Text); if (channel == null) { strError = "channel == null"; return -1; } int nRet = channel.UiLogin("请用root用户身份登录,以便重设代理帐户密码。", "", LoginStyle.None, out strError); if (nRet == -1 || nRet == 0) { strError = "以root用户身份登录失败: " + strError; return -1; } // 获得用户库名 string strRecPath = ""; string strXml = ""; byte[] baTimeStamp = null; // 查重,看这个用户名是否已经存在 // 获得用户记录 // return: // -1 error // 0 not found // >=1 检索命中的条数 nRet = GetUserRecord( channel, this.textBox_manageUserName.Text, out strRecPath, out strXml, out baTimeStamp, out strError); if (nRet == -1) { strError = "获取用户 '" + this.textBox_manageUserName.Text + "' 信息时发生错误: " + strError; return -1; } if (nRet == 0) { strError = "用户 '" + this.textBox_manageUserName.Text + "' 尚不存在,因此无法重设其密码。请直接创建。"; return -1; } if (nRet > 1) { strError = "以 '" + this.textBox_manageUserName.Text + "' 为用户名 的用户记录存在多条,这是一个严重错误,请利用root身份启用dp2manager尽快修正此错误。"; return -1; } // 修改密码 nRet = ResetUserRecordPassword(ref strXml, out strError); if (nRet == -1) { strError = "构造用户记录时发生错误: " + strError; return -1; } string strOutputPath = ""; byte[] baOutputTimeStamp; if (strRecPath == "") { Debug.Assert(false, "不可能出现的情况。"); strRecPath = Defs.DefaultUserDb.Name + "/" + "?"; } long lRet = channel.DoSaveTextRes( strRecPath, strXml, false, // bInlucdePreamble "", // style baTimeStamp, // baTimeStamp, out baOutputTimeStamp, out strOutputPath, out strError); if (lRet == -1) { strError = "保存用户记录时发生错误: " + strError; return -1; } channel.DoLogout(out strError); return 0; }
private void CfgFileEditDlg_Load(object sender, System.EventArgs e) { button_export.Enabled = false; MemoryStream stream = null; string strMetaData; string strError = ""; string strMime = ""; Hashtable values = null; if (Obj != null) { if (this.Obj.Content != null) { stream = new MemoryStream(this.Obj.Content); this.Stream = stream; this.Stream.Seek(0, SeekOrigin.Begin); button_export.Enabled = true; } this.TimeStamp = this.Obj.TimeStamp; strMetaData = this.Obj.Metadata; // 观察mime // 取metadata values = StringUtil.ParseMetaDataXml(strMetaData, out strError); if (values == null) { MessageBox.Show(this, strError); return; } strMime = (string)values["mimetype"]; if (strMime == null || strMime == "") { strMime = "text"; } this.Mime = strMime; this.LocalPath = (string)values["localpath"]; if (this.LocalPath == null) { this.LocalPath = ""; } this.textBox_content.Text = ""; // string strFirstPart = StringUtil.GetFirstPartPath(ref strMime); if (this.IsText == true) { if (this.Stream != null) { this.Stream.Seek(0, SeekOrigin.Begin); using (StreamReader sr = new StreamReader(this.Stream, Encoding.UTF8)) { this.textBox_content.Text = ConvertCrLf(sr.ReadToEnd()); } } } else { } ////// button_OK.Enabled = false; this.textBox_content.SelectionStart = 0; this.textBox_content.SelectionLength = 0; return; } this.channel = Channels.GetChannel(this.ServerUrl); Debug.Assert(channel != null, "Channels.GetChannel() 异常"); DigitalPlatform.Stop stop = null; if (stopManager != null) { stop = new DigitalPlatform.Stop(); stop.Register(this.stopManager, true); // 和容器关联 stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载配置文件: " + this.Path); stop.BeginLoop(); } // string strContent = ""; byte[] baTimeStamp = null; string strOutputPath; string strStyle = "content,data,metadata,timestamp,outputpath"; // string strStyle = "attachment,data,metadata,timestamp,outputpath"; stream = new MemoryStream(); long lRet = channel.GetRes( this.Path, stream, stop, // stop, strStyle, null, // byte [] input_timestamp, out strMetaData, out baTimeStamp, out strOutputPath, out strError); /* * long lRet = channel.GetRes(( * this.Path, * out strContent, * out strMetaData, * out baTimeStamp, * out strOutputPath, * out strError); */ if (stopManager != null) { stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); } if (lRet == -1) { MessageBox.Show(this, strError); goto FINISH; } this.Stream = stream; this.Stream.Seek(0, SeekOrigin.Begin); button_export.Enabled = true; this.TimeStamp = baTimeStamp; // 观察mime // 取metadata values = StringUtil.ParseMetaDataXml(strMetaData, out strError); if (values == null) { MessageBox.Show(this, strError); goto FINISH; } strMime = (string)values["mimetype"]; if (strMime == null || strMime == "") { strMime = "text"; } this.Mime = strMime; this.LocalPath = (string)values["localpath"]; if (this.LocalPath == null) { this.LocalPath = ""; } // string strFirstPart = StringUtil.GetFirstPartPath(ref strMime); if (this.IsText == true) { this.Stream.Seek(0, SeekOrigin.Begin); using (StreamReader sr = new StreamReader(this.Stream, Encoding.UTF8)) { this.textBox_content.Text = ConvertCrLf(sr.ReadToEnd()); } // 注意,此后 this.Stream 被关闭 } else { //this.textBox_content.Text = "<二进制内容无法直接编辑>"; //this.textBox_content.ReadOnly = true; //this.button_format.Enabled = false; } ////// button_OK.Enabled = false; FINISH: if (stopManager != null && stop != null) { stop.Unregister(); // 和容器关联 stop = null; } this.channel = null; this.textBox_content.SelectionStart = 0; this.textBox_content.SelectionLength = 0; }
/* <root> <operation>repairBorrowInfo</operation> <action>...</action> 具体动作 有 repairreaderside repairitemside <readerBarcode>...</readerBarcode> <itemBarcode>...</itemBarcode> <confirmItemRecPath>...</confirmItemRecPath> 辅助判断用的册记录路径 <operator>test</operator> <operTime>Fri, 08 Dec 2006 10:12:20 GMT</operTime> </root> * * * */ public int RecoverRepairBorrowInfo( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, Stream attachmentLog, out string strError) { strError = ""; int nRet = 0; // 暂时把Robust当作Logic处理 if (level == RecoverLevel.Robust) level = RecoverLevel.Logic; long lRet = 0; // int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } bool bReuse = false; // 是否能够不顾RecorverLevel状态而重用部分代码 DO_SNAPSHOT: // 快照恢复 if (level == RecoverLevel.Snapshot || bReuse == true) { string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); string strReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "readerBarcode"); if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "<readerBarcode>元素值为空"; goto ERROR1; } // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { if (strAction == "repairreaderside") { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; goto ERROR1; } // 从实体侧恢复的时候,是允许读者记录不存在的 } if (nRet == -1) { strError = "读入证条码号为 '" + strReaderBarcode + "' 的读者记录时发生错误: " + strError; goto ERROR1; } XmlDocument readerdom = null; if (string.IsNullOrEmpty(strReaderXml) == false) { nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } } // 校验读者证条码号参数是否和XML记录中完全一致 if (readerdom != null) { string strTempBarcode = DomUtil.GetElementText(readerdom.DocumentElement, "barcode"); if (strReaderBarcode != strTempBarcode) { strError = "修复操作被拒绝。因读者证条码号参数 '" + strReaderBarcode + "' 和读者记录中<barcode>元素内的读者证条码号值 '" + strTempBarcode + "' 不一致。"; goto ERROR1; } } // 读入册记录 string strConfirmItemRecPath = DomUtil.GetElementText(domLog.DocumentElement, "confirmItemRecPath"); string strItemBarcode = DomUtil.GetElementText(domLog.DocumentElement, "itemBarcode"); if (String.IsNullOrEmpty(strItemBarcode) == true) { strError = "<strItemBarcode>元素值为空"; goto ERROR1; } string strItemXml = ""; string strOutputItemRecPath = ""; byte[] item_timestamp = null; // 如果已经有确定的册记录路径 if (String.IsNullOrEmpty(strConfirmItemRecPath) == false) { string strMetaData = ""; lRet = channel.GetRes(strConfirmItemRecPath, out strItemXml, out strMetaData, out item_timestamp, out strOutputItemRecPath, out strError); if (lRet == -1) { strError = "根据strConfirmItemRecPath '" + strConfirmItemRecPath + "' 获得册记录失败: " + strError; goto ERROR1; } // 需要检查记录中的<barcode>元素值是否匹配册条码号 // TODO: 如果记录路径所表达的记录不存在,或者其<barcode>元素值和要求的册条码号不匹配,那么都要改用逻辑方法,也就是利用册条码号来获得记录。 // 当然,这种情况下,非常要紧的是确保数据库的素质很好,本身没有重条码号的情况出现。 } else { // 从册条码号获得册记录 List<string> aPath = null; // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( // Channels, channel, strItemBarcode, out strItemXml, 100, out aPath, out item_timestamp, out strError); if (nRet == 0) { if (strAction == "repairitemside") { strError = "册条码号 '" + strItemBarcode + "' 不存在"; goto ERROR1; } // 从读者侧恢复的时候,册条码号不存在是允许的 goto CONTINUE_REPAIR; } if (nRet == -1) { strError = "读入册条码号为 '" + strItemBarcode + "' 的册记录时发生错误: " + strError; goto ERROR1; } if (aPath.Count > 1) { strError = "册条码号为 '" + strItemBarcode + "' 的册记录有 " + aPath.Count.ToString() + " 条,但此时comfirmItemRecPath却为空"; goto ERROR1; } else { Debug.Assert(nRet == 1, ""); Debug.Assert(aPath.Count == 1, ""); if (nRet == 1) { strOutputItemRecPath = aPath[0]; } } } CONTINUE_REPAIR: XmlDocument itemdom = null; if (string.IsNullOrEmpty(strItemXml) == false) { nRet = LibraryApplication.LoadToDom(strItemXml, out itemdom, out strError); if (nRet == -1) { strError = "装载册记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // 校验册条码号参数是否和XML记录中完全一致 string strTempItemBarcode = DomUtil.GetElementText(itemdom.DocumentElement, "barcode"); if (strItemBarcode != strTempItemBarcode) { strError = "修复操作被拒绝。因册条码号参数 '" + strItemBarcode + "' 和册记录中<barcode>元素内的册条码号值 '" + strTempItemBarcode + "' 不一致。"; goto ERROR1; } } if (strAction == "repairreaderside") { XmlNode nodeBorrow = readerdom.DocumentElement.SelectSingleNode("borrows/borrow[@barcode='" + strItemBarcode + "']"); if (nodeBorrow == null) { strError = "修复操作被拒绝。读者记录 " + strReaderBarcode + " 中并不存在有关册 " + strItemBarcode + " 的借阅信息。"; goto ERROR1; } if (itemdom != null) { // 看看册记录中是否有指回读者记录的链 string strBorrower = DomUtil.GetElementText(itemdom.DocumentElement, "borrower"); if (strBorrower == strReaderBarcode) { strError = "修复操作被拒绝。您所请求要修复的链,本是一条完整正确的链。可直接进行普通还书操作。"; goto ERROR1; } } // 移除读者记录侧的链 nodeBorrow.ParentNode.RemoveChild(nodeBorrow); byte[] output_timestamp = null; string strOutputPath = ""; // 写回读者记录 lRet = channel.DoSaveTextRes(strOutputReaderRecPath, readerdom.OuterXml, false, "content,ignorechecktimestamp", reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } else if (strAction == "repairitemside") { // 看看册记录中是否有指向读者记录的链 string strBorrower = DomUtil.GetElementText(itemdom.DocumentElement, "borrower"); if (String.IsNullOrEmpty(strBorrower) == true) { strError = "修复操作被拒绝。您所请求要修复的册记录中,本来就没有借阅信息,因此谈不上修复。"; goto ERROR1; } if (strBorrower != strReaderBarcode) { strError = "修复操作被拒绝。您所请求要修复的册记录中,并没有指明借阅者是读者 " + strReaderBarcode + "。"; goto ERROR1; } // 看看读者记录中是否有指回链条。 if (readerdom != null) { XmlNode nodeBorrow = readerdom.DocumentElement.SelectSingleNode("borrows/borrow[@barcode='" + strItemBarcode + "']"); if (nodeBorrow != null) { strError = "修复操作被拒绝。您所请求要修复的链,本是一条完整正确的链。可直接进行普通还书操作。"; goto ERROR1; } } // 移除册记录侧的链 DomUtil.SetElementText(itemdom.DocumentElement, "borrower", ""); DomUtil.SetElementText(itemdom.DocumentElement, "borrowDate", ""); DomUtil.SetElementText(itemdom.DocumentElement, "borrowPeriod", ""); byte[] output_timestamp = null; string strOutputPath = ""; // 写回册记录 lRet = channel.DoSaveTextRes(strOutputItemRecPath, itemdom.OuterXml, false, "content,ignorechecktimestamp", item_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } else { strError = "不可识别的strAction值 '"+strAction+"'"; goto ERROR1; } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { // 和SnapShot方式相同 bReuse = true; goto DO_SNAPSHOT; } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
// 填充listview public int Fill(string strLang, out string strError) { listView_users.Items.Clear(); strError = ""; string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(Defs.DefaultUserDb.Name) // 2007/9/14 + ":" + "__id'><item><word>" + "" + "</word><match>left</match><relation>=</relation><dataType>string</dataType><maxCount>10</maxCount></item><lang>zh</lang></target>"; RmsChannel channel = Channels.GetChannel(this.ServerUrl); if (channel == null) { strError = "Channels.GetChannel 异常"; return(-1); } long nRet = channel.DoSearch(strQueryXml, "default", "", // strOuputStyle out strError); if (nRet == -1) { strError = "检索帐户库时出错: " + strError; return(-1); } if (nRet == 0) { return(0); // not found } long lTotalCount = nRet; // 总命中数 long lThisCount = lTotalCount; long lStart = 0; for (;;) { ArrayList aLine = null; nRet = channel.DoGetSearchFullResult( "default", lStart, lThisCount, strLang, null, // stop, out aLine, out strError); if (nRet == -1) { strError = "检索注册用户库获取检索结果时出错: " + strError; return(-1); } for (int i = 0; i < aLine.Count; i++) { string[] acol = (string[])aLine[i]; if (acol.Length < 1) { continue; } if (acol.Length < 2) { // 列中没有用户名, 用获取记录来补救? } ListViewItem item = new ListViewItem(acol[1], 0); this.listView_users.Items.Add(item); item.SubItems.Add(acol[0]); } if (lStart + aLine.Count >= lTotalCount) { break; } lStart += aLine.Count; lThisCount -= aLine.Count; } return(0); }
// Return() API 恢复动作 /* 日志记录格式 <root> <operation>return</operation> 操作类型 <itemBarcode>0000001</itemBarcode> 册条码号 <readerBarcode>R0000002</readerBarcode> 读者证条码号 <operator>test</operator> 操作者 <operTime>Fri, 08 Dec 2006 04:17:45 GMT</operTime> 操作时间 <overdues>...</overdues> 超期信息 通常内容为一个字符串,为一个<overdue>元素XML文本片断 <confirmItemRecPath>...</confirmItemRecPath> 辅助判断用的册记录路径 <readerRecord recPath='...'>...</readerRecord> 最新读者记录 <itemRecord recPath='...'>...</itemRecord> 最新册记录 </root> * * */ // parameters: // bForce 是否为容错状态。在容错状态下,如果遇到重复的册条码号,就算做第一条。 public int RecoverReturn( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, bool bForce, out string strError) { strError = ""; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } DO_SNAPSHOT: // 快照恢复 if (level == RecoverLevel.Snapshot) { XmlNode node = null; string strReaderXml = DomUtil.GetElementText(domLog.DocumentElement, "readerRecord", out node); if (node == null) { strError = "日志记录中缺<readerRecord>元素"; return -1; } string strReaderRecPath = DomUtil.GetAttr(node, "recPath"); string strItemXml = DomUtil.GetElementText(domLog.DocumentElement, "itemRecord", out node); if (node == null) { strError = "日志记录中缺<itemRecord>元素"; return -1; } string strItemRecPath = DomUtil.GetAttr(node, "recPath"); byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; // 写读者记录 lRet = channel.DoSaveTextRes(strReaderRecPath, strReaderXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入读者记录 '" + strReaderRecPath + "' 时发生错误: " + strError; return -1; } // 写册记录 lRet = channel.DoSaveTextRes(strItemRecPath, strItemXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入读者记录 '" + strReaderRecPath + "' 时发生错误: " + strError; return -1; } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { string strRecoverComment = ""; string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); string strReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "readerBarcode"); // 读入册记录 string strConfirmItemRecPath = DomUtil.GetElementText(domLog.DocumentElement, "confirmItemRecPath"); string strItemBarcode = DomUtil.GetElementText(domLog.DocumentElement, "itemBarcode"); if (String.IsNullOrEmpty(strItemBarcode) == true) { strError = "<strItemBarcode>元素值为空"; goto ERROR1; } string strItemXml = ""; string strOutputItemRecPath = ""; byte[] item_timestamp = null; // 如果已经有确定的册记录路径 if (String.IsNullOrEmpty(strConfirmItemRecPath) == false) { string strMetaData = ""; lRet = channel.GetRes(strConfirmItemRecPath, out strItemXml, out strMetaData, out item_timestamp, out strOutputItemRecPath, out strError); if (lRet == -1) { strError = "根据strConfirmItemRecPath '" + strConfirmItemRecPath + "' 获得册记录失败: " + strError; goto ERROR1; } // 需要检查记录中的<barcode>元素值是否匹配册条码号 } else { // 从册条码号获得册记录 List<string> aPath = null; // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( // Channels, channel, strItemBarcode, out strItemXml, 100, out aPath, out item_timestamp, out strError); if (nRet == 0) { strError = "册条码号 '" + strItemBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入册条码号为 '" + strItemBarcode + "' 的册记录时发生错误: " + strError; goto ERROR1; } if (aPath.Count > 1) { if (string.IsNullOrEmpty(strReaderBarcode) == true) { // 发生重条码号的时候,又没有读者证条码号辅助判断 if (bForce == false) { strError = "册条码号为 '" + strItemBarcode + "' 的册记录有 " + aPath.Count.ToString() + " 条,但此时日志记录中没有提供读者证条码号辅助判断,无法进行还书操作。"; goto ERROR1; } // TODO: 那就至少看看这些册中,哪些表明被人借阅着?如果正巧只有一个人借过,那就...。 strRecoverComment += "册条码号 " + strItemBarcode + "有 " + aPath.Count.ToString() + " 条重复记录,而且没有读者证条码号进行辅助选择。"; } /* strError = "册条码号为 '" + strItemBarcode + "' 的册记录有 " + aPath.Count.ToString() + " 条,但此时comfirmItemRecPath却为空"; goto ERROR1; * */ // bItemBarcodeDup = true; // 此时已经需要设置状态。虽然后面可以进一步识别出真正的册记录 /* // 构造strDupBarcodeList string[] pathlist = new string[aPath.Count]; aPath.CopyTo(pathlist); strDupBarcodeList = String.Join(",", pathlist); * */ List<string> aFoundPath = null; List<byte[]> aTimestamp = null; List<string> aItemXml = null; // 从若干重复条码号的册记录中,选出其中符合当前读者证条码号的 // return: // -1 出错 // 其他 选出的数量 nRet = FindItem( channel, strReaderBarcode, aPath, true, // 优化 out aFoundPath, out aItemXml, out aTimestamp, out strError); if (nRet == -1) { strError = "选择重复条码号的册记录时发生错误: " + strError; goto ERROR1; } if (nRet == 0) { strError = "册条码号 '" + strItemBarcode + "' 检索出的 " + aPath.Count + " 条记录中,没有任何一条其<borrower>元素表明了被读者 '" + strReaderBarcode + "' 借阅。"; goto ERROR1; } if (nRet > 1) { if (bForce == true) { // 容错情况下,选择第一个册条码号 strOutputItemRecPath = aFoundPath[0]; item_timestamp = aTimestamp[0]; strItemXml = aItemXml[0]; // TODO: 不过,应当在记录中记载注释,表示这是容错处理方式 if (string.IsNullOrEmpty(strReaderBarcode) == true) { strRecoverComment += "经过筛选,仍然有 " + aFoundPath.Count.ToString() + " 条册记录含有借阅者信息(无论什么读者证条码号),那么就只好选择其中第一个册记录 " + strOutputItemRecPath + " 进行还书操作。"; } else { strRecoverComment += "经过筛选,仍然有 " + aFoundPath.Count.ToString() + " 条册记录含有借阅者 '"+strReaderBarcode+"' 信息,那么就只好选择其中第一个册记录 " + strOutputItemRecPath + " 进行还书操作。"; } } else { strError = "册条码号为 '" + strItemBarcode + "' 并且<borrower>元素表明为读者 '" + strReaderBarcode + "' 借阅的册记录有 " + aFoundPath.Count.ToString() + " 条,无法进行还书操作。"; /* aDupPath = new string[aFoundPath.Count]; aFoundPath.CopyTo(aDupPath); * */ goto ERROR1; } } Debug.Assert(nRet == 1, ""); strOutputItemRecPath = aFoundPath[0]; item_timestamp = aTimestamp[0]; strItemXml = aItemXml[0]; } else { Debug.Assert(nRet == 1, ""); Debug.Assert(aPath.Count == 1, ""); if (nRet == 1) { strOutputItemRecPath = aPath[0]; } } } XmlDocument itemdom = null; nRet = LibraryApplication.LoadToDom(strItemXml, out itemdom, out strError); if (nRet == -1) { strError = "装载册记录进入XML DOM时发生错误: " + strError; goto ERROR1; } /// if (String.IsNullOrEmpty(strReaderBarcode) == true) { if (bForce == true) { // 容错的情况下,从册记录中获得借者证条码号 strReaderBarcode = DomUtil.GetElementText(itemdom.DocumentElement, "borrower"); if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "在不知道读者证条码号的情况下,册记录中的<borrower>元素值为空。无法进行还书操作。"; goto ERROR1; } } else { strError = "日志记录中<readerBarcode>元素值为空"; goto ERROR1; } } // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入证条码号为 '" + strReaderBarcode + "' 的读者记录时发生错误: " + strError; goto ERROR1; } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // 修改读者记录 // 修改册记录 nRet = ReturnChangeReaderAndItemRecord( // Channels, channel, strAction, strItemBarcode, strReaderBarcode, domLog, strRecoverComment, ref readerdom, ref itemdom, out strError); if (nRet == -1) goto ERROR1; // 写回读者、册记录 byte[] output_timestamp = null; string strOutputPath = ""; // 写回读者记录 lRet = channel.DoSaveTextRes(strOutputReaderRecPath, readerdom.OuterXml, false, "content,ignorechecktimestamp", reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; // 写回册记录 lRet = channel.DoSaveTextRes(strOutputItemRecPath, itemdom.OuterXml, false, "content,ignorechecktimestamp", item_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } // 容错恢复 if (level == RecoverLevel.Robust) { string strRecoverComment = ""; string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); string strReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "readerBarcode"); // 读入册记录 string strConfirmItemRecPath = DomUtil.GetElementText(domLog.DocumentElement, "confirmItemRecPath"); string strItemBarcode = DomUtil.GetElementText(domLog.DocumentElement, "itemBarcode"); if (String.IsNullOrEmpty(strItemBarcode) == true) { strError = "<strItemBarcode>元素值为空"; goto ERROR1; } string strItemXml = ""; string strOutputItemRecPath = ""; byte[] item_timestamp = null; // 从册条码号获得册记录 List<string> aPath = null; bool bDupItemBarcode = false; // 册条码号是否发生了重复 // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( // Channels, channel, strItemBarcode, out strItemXml, 100, out aPath, out item_timestamp, out strError); if (nRet == 0) { strError = "册条码号 '" + strItemBarcode + "' 不存在"; // TODO: 记入信息文件 XmlNode node = null; strItemXml = DomUtil.GetElementText(domLog.DocumentElement, "itemRecord", out node); if (node == null) { strError = "日志记录中缺<itemRecord>元素"; return -1; } string strItemRecPath = DomUtil.GetAttr(node, "recPath"); if (String.IsNullOrEmpty(strItemRecPath) == true) { strError = "日志记录中<itemRecord>元素缺recPath属性"; return -1; } // 新增一条册记录 strOutputItemRecPath = ResPath.GetDbName(strItemRecPath) + "/?"; item_timestamp = null; } else { if (nRet == -1) { strError = "读入册条码号为 '" + strItemBarcode + "' 的册记录时发生错误: " + strError; return -1; } if (aPath.Count > 1) { bDupItemBarcode = true; if (string.IsNullOrEmpty(strReaderBarcode) == true) { // 发生重条码号的时候,又没有读者证条码号辅助判断 if (bForce == false) { strError = "册条码号为 '" + strItemBarcode + "' 的册记录有 " + aPath.Count.ToString() + " 条,但此时日志记录中没有提供读者证条码号辅助判断,无法进行还书操作。"; return -1; } // TODO: 那就至少看看这些册中,哪些表明被人借阅着?如果正巧只有一个人借过,那就...。 strRecoverComment += "册条码号 " + strItemBarcode + " 有 " + aPath.Count.ToString() + " 条重复记录,而且没有读者证条码号进行辅助选择。"; } List<string> aFoundPath = null; List<byte[]> aTimestamp = null; List<string> aItemXml = null; // 从若干重复条码号的册记录中,选出其中符合当前读者证条码号的 // return: // -1 出错 // 其他 选出的数量 nRet = FindItem( channel, strReaderBarcode, aPath, true, // 优化 out aFoundPath, out aItemXml, out aTimestamp, out strError); if (nRet == -1) { strError = "选择重复条码号的册记录时发生错误: " + strError; return -1; } if (nRet == 0) { if (bDupItemBarcode == false) { // 没有重复册条码号的情况下才作 // 需要把根据“所借册条码号”清除读者记录中借阅信息的动作提前进行? 这样遇到特殊情况范围时,至少读者记录中的信息是被清除了的,这是容错的需要 string strError_1 = ""; nRet = ReturnAllReader( // Channels, channel, strItemBarcode, "", out strError_1); if (nRet == -1) { // 故意不报,继续处理 } } strError = "册条码号 '" + strItemBarcode + "' 检索出的 " + aPath.Count + " 条记录中,没有任何一条其<borrower>元素表明了被读者 '" + strReaderBarcode + "' 借阅。"; return -1; } if (nRet > 1) { if (bForce == true) { // 容错情况下,选择第一个册条码号 strOutputItemRecPath = aFoundPath[0]; item_timestamp = aTimestamp[0]; strItemXml = aItemXml[0]; // TODO: 不过,应当在记录中记载注释,表示这是容错处理方式 if (string.IsNullOrEmpty(strReaderBarcode) == true) { strRecoverComment += "经过筛选,仍然有 " + aFoundPath.Count.ToString() + " 条册记录含有借阅者信息(无论什么读者证条码号),那么就只好选择其中第一个册记录 " + strOutputItemRecPath + " 进行还书操作。"; } else { strRecoverComment += "经过筛选,仍然有 " + aFoundPath.Count.ToString() + " 条册记录含有借阅者 '" + strReaderBarcode + "' 信息,那么就只好选择其中第一个册记录 " + strOutputItemRecPath + " 进行还书操作。"; } } else { strError = "册条码号为 '" + strItemBarcode + "' 并且<borrower>元素表明为读者 '" + strReaderBarcode + "' 借阅的册记录有 " + aFoundPath.Count.ToString() + " 条,无法进行还书操作。"; return -1; } } Debug.Assert(nRet == 1, ""); strOutputItemRecPath = aFoundPath[0]; item_timestamp = aTimestamp[0]; strItemXml = aItemXml[0]; } else { Debug.Assert(nRet == 1, ""); Debug.Assert(aPath.Count == 1, ""); if (nRet == 1) { strOutputItemRecPath = aPath[0]; } } } //// XmlDocument itemdom = null; nRet = LibraryApplication.LoadToDom(strItemXml, out itemdom, out strError); if (nRet == -1) { strError = "装载册记录进入XML DOM时发生错误: " + strError; goto ERROR1; } /// if (String.IsNullOrEmpty(strReaderBarcode) == true) { if (bForce == true) { // 容错的情况下,从册记录中获得借者证条码号 strReaderBarcode = DomUtil.GetElementText(itemdom.DocumentElement, "borrower"); if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "在不知道读者证条码号的情况下,册记录中的<borrower>元素值为空。无法进行还书操作。"; return -1; } } else { strError = "日志记录中<readerBarcode>元素值为空"; return -1; } } // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; // TODO: 记入信息文件 // 从日志记录中获得读者记录 XmlNode node = null; strReaderXml = DomUtil.GetElementText(domLog.DocumentElement, "readerRecord", out node); if (node == null) { strError = "日志记录中缺<readerRecord>元素"; return -1; } string strReaderRecPath = DomUtil.GetAttr(node, "recPath"); if (String.IsNullOrEmpty(strReaderRecPath) == true) { strError = "日志记录中<readerRecord>元素缺recPath属性"; return -1; } // 新增一条读者记录 strOutputReaderRecPath = ResPath.GetDbName(strReaderRecPath) + "/?"; reader_timestamp = null; } else { if (nRet == -1) { strError = "读入证条码号为 '" + strReaderBarcode + "' 的读者记录时发生错误: " + strError; return -1; } } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; return -1; } // 修改读者记录 // 修改册记录 nRet = ReturnChangeReaderAndItemRecord( // Channels, channel, strAction, strItemBarcode, strReaderBarcode, domLog, strRecoverComment, ref readerdom, ref itemdom, out strError); if (nRet == -1) return -1; // 在容错(并且没有重复册条码号的情况下)的情况下,需要利用读者库的“所借册条码号”检索途径,把除了当前关注的读者记录以外的潜在相关读者记录调出, // 把它们中的相关<borrows/borrow>抹除,以免造成多头的借阅信息。 if (bDupItemBarcode == false) { nRet = ReturnAllReader( // Channels, channel, strItemBarcode, strOutputReaderRecPath, out strError); if (nRet == -1) { // 故意不报,继续处理 } } //// // 写回读者、册记录 byte[] output_timestamp = null; string strOutputPath = ""; // 写回读者记录 lRet = channel.DoSaveTextRes(strOutputReaderRecPath, readerdom.OuterXml, false, "content,ignorechecktimestamp", reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) return -1; // 写回册记录 lRet = channel.DoSaveTextRes(strOutputItemRecPath, itemdom.OuterXml, false, "content,ignorechecktimestamp", item_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) return -1; } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
private void button_OK_Click(object sender, System.EventArgs e) { if (textBox_url.Text == "") { MessageBox.Show(this, "尚未指定服务器URL..."); return; } if (textBox_newPassword.Text != textBox_newPasswordConfirm.Text) { MessageBox.Show(this, "新密码和确认密码不一致,请重新输入..."); return; } if (textBox_userName.Text == "") { MessageBox.Show(this, "尚未输入用户名。"); return; } channel = Channels.GetChannel(textBox_url.Text); Debug.Assert(channel != null, "Channels.GetChannel 异常"); stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在修改密码..."); stop.BeginLoop(); int nRet; string strError; EnableControls(false); button_Cancel.Text = "中断"; nRet = channel.ChangePassword( textBox_userName.Text, textBox_oldPassword.Text, textBox_newPassword.Text, checkBox_manager.Checked, out strError); EnableControls(true); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); button_Cancel.Enabled = true; // 因为Cancel按钮还有退出对话框的功能 button_Cancel.Text = "取消"; if (nRet == -1) { goto ERROR1; } channel = null; MessageBox.Show(this, "密码修改成功。"); this.DialogResult = DialogResult.OK; this.Close(); return; ERROR1: button_Cancel.Enabled = true; button_Cancel.Text = "取消"; channel = null; MessageBox.Show(this, "修改密码失败,原因:" + strError); }
// 递归 public int Fill(TreeNode node) { TreeNodeCollection children = null; if (node == null) { children = this.Nodes; } else { children = node.Nodes; } int i; // 填充根 if (node == null) { children.Clear(); TreeNode nodeNew = new TreeNode(this.ServerUrl, ResTree.RESTYPE_SERVER, ResTree.RESTYPE_SERVER); ResTree.SetLoading(nodeNew); NodeInfo nodeinfo = new NodeInfo(); nodeinfo.TreeNode = nodeNew; nodeinfo.Expandable = true; nodeinfo.DefElement = GetDefElementString(nodeNew.ImageIndex); nodeinfo.NodeState |= NodeState.Object; nodeNew.Tag = nodeinfo; if (EnabledIndices != null && StringUtil.IsInList(nodeNew.ImageIndex, EnabledIndices) == false) { nodeNew.ForeColor = ControlPaint.LightLight(nodeNew.ForeColor); } children.Add(nodeNew); return(0); } // 根以下的节点类型 ResPath respath = new ResPath(node); string strPath = respath.Path; //if (node != null) // strPath = TreeViewUtil.GetPath(node); this.channel = Channels.GetChannel(this.ServerUrl); Debug.Assert(channel != null, "Channels.GetChannel() 异常"); ResInfoItem[] items = null; string strError = ""; DigitalPlatform.Stop stop = null; if (stopManager != null) { stop = new DigitalPlatform.Stop(); stop.Register(this.stopManager, true); // 和容器关联 stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在列目录: " + this.ServerUrl + "?" + strPath); stop.BeginLoop(); } long lRet = channel.DoDir(strPath, this.Lang, null, // 不需要列出全部语言的名字 out items, out strError); if (stopManager != null) { stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); stop.Unregister(); // 和容器关联 } this.channel = null; if (lRet == -1) { try { MessageBox.Show(this, "Channel::DoDir() Error: " + strError); } catch { // this可能已经不存在 return(-1); } if (node != null) { ResTree.SetLoading(node); // 出错的善后处理,重新出现+号 node.Collapse(); } return(-1); } if (items != null) { children.Clear(); for (i = 0; i < items.Length; i++) { // 忽略from类型节点 if (items[i].Type == ResTree.RESTYPE_FROM) { continue; } TreeNode nodeNew = new TreeNode(items[i].Name, items[i].Type, items[i].Type); NodeInfo nodeinfo = new NodeInfo(); nodeinfo.TreeNode = nodeNew; nodeinfo.Expandable = items[i].HasChildren; nodeinfo.DefElement = GetDefElementString(nodeNew.ImageIndex); nodeinfo.NodeState |= NodeState.Object; nodeinfo.Style = items[i].Style; nodeNew.Tag = nodeinfo; if (items[i].HasChildren) { ResTree.SetLoading(nodeNew); } if (EnabledIndices != null && StringUtil.IsInList(nodeNew.ImageIndex, EnabledIndices) == false) { nodeNew.ForeColor = ControlPaint.LightLight(nodeNew.ForeColor); } children.Add(nodeNew); } } return(0); }
// 检索文章 // return: // -1 error // 其他 命中数 public int Search( string strServerUrl, string strQueryXml, RmsChannelCollection Channels, string strLang, out string strError) { strError = ""; string strMessage = ""; // 加写锁 this.m_lock.AcquireWriterLock(m_nLockTimeout); try { this.File.Clear(); // 清空集合 //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; RmsChannel channel = Channels.GetChannel(strServerUrl); Debug.Assert(channel != null, "Channels.GetChannel 异常"); strMessage += "--- begin search ...\r\n"; DateTime time = DateTime.Now; //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; long nRet = channel.DoSearch(strQueryXml, "default", "", // strOuputStyle out strError); if (nRet == -1) { strError = "检索时出错: " + strError; return(-1); } TimeSpan delta = DateTime.Now - time; strMessage += "search end. time=" + delta.ToString() + "\r\n"; if (nRet == 0) { return(0); // not found } long lTotalCount = nRet; //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; strMessage += "--- begin get search result ...\r\n"; time = DateTime.Now; long lStart = 0; long lPerCount = Math.Min(lTotalCount, 1000); for (; ;) { //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; lPerCount = Math.Min((lTotalCount - lStart), 1000); nRet = channel.DoGetSearchResult( "default", lStart, lPerCount, strLang, null, // stop, out List <string> aPath, out strError); if (nRet == -1) { strError = "检索库时出错: " + strError; return(-1); } delta = DateTime.Now - time; strMessage += "get search result end. time=" + delta.ToString() + "\r\n"; if (aPath.Count == 0) { strError = "检索库时获取的检索结果为空"; return(-1); } //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; strMessage += "--- begin build storage ...\r\n"; time = DateTime.Now; int i; // 加入新行对象。新行对象中,只初始化了m_strRecID参数 for (i = 0; i < aPath.Count; i++) { ClientRecordItem item = new ClientRecordItem(); item.Path = (string)aPath[i]; this.File.Add(item); if ((i % 100) == 0) { strMessage += "process " + Convert.ToString(i) + "\r\n"; } } delta = DateTime.Now - time; strMessage += "build storage end. time=" + delta.ToString() + "\r\n"; lStart += aPath.Count; if (lStart >= lTotalCount) { break; } } return(1); } finally { this.m_lock.ReleaseWriterLock(); } }
// 获得期刊记录 // 本函数可获得超过1条以上的路径 // parameters: // timestamp 返回命中的第一条的timestamp // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 public int GetIssueRecXml( RmsChannelCollection channels, string strIssueDbName, string strParentID, string strPublishTime, out string strXml, int nMax, out List<string> aPath, out byte[] timestamp, out string strError) { aPath = null; strXml = ""; strError = ""; timestamp = null; LibraryApplication app = this; // 构造检索式 // 构造检索式 string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strIssueDbName + ":" + "出版时间") + "'><item><word>" + StringUtil.GetXmlStringSimple(strPublishTime) + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>zh</lang></target>"; strQueryXml += "<operator value='AND'/>"; strQueryXml += "<target list='" + StringUtil.GetXmlStringSimple(strIssueDbName + ":" + "父记录") + "'><item><word>" + StringUtil.GetXmlStringSimple(strParentID) + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>zh</lang></target>"; strQueryXml = "<group>" + strQueryXml + "</group>"; RmsChannel channel = channels.GetChannel(app.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } long lRet = channel.DoSearch(strQueryXml, "default", out strError); if (lRet == -1) goto ERROR1; // not found if (lRet == 0) { strError = "册条码号 '" + strPublishTime + "' 没有找到"; return 0; } long lHitCount = lRet; // List<string> aPath = null; lRet = channel.DoGetSearchResult( "default", 0, Math.Min(nMax, lHitCount), "zh", null, out aPath, out strError); if (lRet == -1) goto ERROR1; Debug.Assert(aPath != null, ""); if (aPath.Count == 0) { strError = "DoGetSearchResult aPath error"; goto ERROR1; } string strMetaData = ""; string strOutputPath = ""; lRet = channel.GetRes(aPath[0], out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; return (int)lHitCount; ERROR1: return -1; }
// 根据 父记录ID/出版时间 对期库进行查重 // 本函数只负责查重, 并不获得记录体 // return: // -1 error // 其他 命中记录条数(不超过nMax规定的极限) public int SearchIssueRecDup( RmsChannelCollection channels, string strIssueDbName, string strParentID, string strPublishTime, int nMax, out List<string> aPath, out string strError) { strError = ""; aPath = null; LibraryApplication app = this; // 构造检索式 string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strIssueDbName + ":" + "出版时间") + "'><item><word>" + StringUtil.GetXmlStringSimple(strPublishTime) + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>zh</lang></target>"; strQueryXml += "<operator value='AND'/>"; strQueryXml += "<target list='" + StringUtil.GetXmlStringSimple(strIssueDbName + ":" + "父记录") + "'><item><word>" + StringUtil.GetXmlStringSimple(strParentID) + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>zh</lang></target>"; strQueryXml = "<group>" + strQueryXml + "</group>"; RmsChannel channel = channels.GetChannel(app.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } long lRet = channel.DoSearch(strQueryXml, "default", out strError); if (lRet == -1) goto ERROR1; // not found if (lRet == 0) { strError = "出版时间为 '" + strPublishTime + "' 并且 父记录为 '"+strParentID+"' 的记录没有找到"; return 0; } long lHitCount = lRet; lRet = channel.DoGetSearchResult( "default", 0, nMax, "zh", null, out aPath, out strError); if (lRet == -1) goto ERROR1; if (aPath.Count == 0) { strError = "DoGetSearchResult aPath error 和前面已经命中的条件矛盾"; goto ERROR1; } return (int)lHitCount; ERROR1: return -1; }
// 检索获得消息, 或者从结果集中获得消息 // parameters: // strStyle search / untouched / touched // 有search表示进行检索和获取,没有search就表示不检索而获取先前检索的结果集。 // untoched和touched应当和search联用。否则只能获取先前的结果数 public int GetMessage( RmsChannelCollection Channels, string strResultsetName, string strStyle, string strUserID, string strBoxType, MessageLevel messagelevel, int nStart, int nCount, out int nTotalCount, out List<MessageData> messages, out string strError) { nTotalCount = 0; messages = new List<MessageData>(); strError = ""; if (String.IsNullOrEmpty(this.MessageDbName) == true) { strError = "消息库尚未定义"; return -1; } int nRet = 0; long lRet = 0; if (String.IsNullOrEmpty(strBoxType) == true) { strBoxType = MessageCenter.INBOX; } RmsChannel channel = Channels.GetChannel(this.ServerUrl); if (channel == null) { strError = "get channel error"; return -1; } if (String.IsNullOrEmpty(strResultsetName) == true) strResultsetName = "messages_of_" + strBoxType; bool bSearch = true; if (StringUtil.IsInList("search", strStyle) == true) bSearch = true; else bSearch = false; string strQueryStyle = ""; if (StringUtil.IsInList("touched", strStyle) == true) strQueryStyle = "touched"; else if (StringUtil.IsInList("untouched", strStyle) == true) strQueryStyle = "untouched"; // 检索 if (bSearch == true) { string strQueryXml = ""; // 构造检索式 nRet = MakeSearchQuery( strUserID, strBoxType, strQueryStyle, out strQueryXml, out strError); if (nRet == -1) { // text-level: 内部错误 strError = "构造检索式出错: " + strError; return -1; } lRet = channel.DoSearch(strQueryXml, strResultsetName, "", // strOuputStyle out strError); if (lRet == -1) { // text-level: 内部错误 strError = "检索失败: " + strError; return -1; } // not found if (lRet == 0) { // text-level: 用户提示 strError = this.GetString("没有任何消息"); // "没有任何消息" return 0; } nTotalCount = (int)lRet; } if (nCount == 0) return nTotalCount; // 如果不需要获得结果集 Debug.Assert(nStart >= 0, ""); // 获得结果集中指定范围的记录路径 ArrayList aLine = null; lRet = channel.DoGetSearchFullResult( strResultsetName, nStart, nCount, "zh", null, out aLine, out strError); if (lRet == -1) { // 虽然返回-1,但是aLine中仍然有内容了 if (aLine == null) { // text-level: 内部错误 strError = "获取浏览格式失败: " + strError; return -1; } } // 返回数据 for (int i = 0; i < aLine.Count; i++) { string[] cols = null; cols = (string[])aLine[i]; string strPath = cols[0]; MessageData data = null; // TODO: level == none 只返回路径 nRet = GetMessageByPath( channel, strPath, messagelevel, out data, out strError); if (nRet == -1) return -1; messages.Add(data); } return aLine.Count; }
// 通过特定检索途径获得读者记录的特定keys值 // return: // -1 error // >=0 命中个数 public int SearchAllIds( RmsChannelCollection channels, string strPatronDbName, string strFrom, out List<string> ids, out string strError) { strError = ""; ids = new List<string>(); Debug.Assert(String.IsNullOrEmpty(strPatronDbName) == false, ""); // 构造检索式 string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strPatronDbName + ":" + strFrom) + "'><item><word></word><match>left</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>zh</lang></target>"; RmsChannel channel = channels.GetChannel(this.App.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } string strOutputStyle = "keyid"; string strBrowseStyle = "keyid,key,id,cols"; long lRet = channel.DoSearch(strQueryXml, "default", strOutputStyle, out strError); if (lRet == -1) goto ERROR1; // not found if (lRet == 0) return 0; long lHitCount = lRet; long lStart = 0; for (; ; ) { #if NO // 2012/2/4 // 系统挂起的时候,不运行本线程 if (this.App.HangupReason == HangupReason.LogRecover) { strError = "因为系统挂起或暂停批处理而中断处理"; return -1; } #endif if (this.Stopped == true) { strError = "中断处理"; return -1; } Record[] records = null; lRet = channel.DoGetSearchResult( "default", lStart, -1, strBrowseStyle, "zh", null, out records, out strError); if (lRet == -1) goto ERROR1; foreach (Record record in records) { Debug.Assert(record.Keys != null && record.Keys.Length > 0, ""); if (record.Keys != null && record.Keys.Length > 0) ids.Add(record.Keys[0].Key); } lStart += records.Length; if (lStart >= lHitCount) break; } return (int)lHitCount; ERROR1: return -1; }
/// <summary> /// 检索实用库 /// </summary> /// <param name="Channels"></param> /// <param name="strServerUrl"></param> /// <param name="strDbName"></param> /// <param name="strFrom"></param> /// <param name="strKey"></param> /// <param name="strXml"></param> /// <param name="strError"></param> /// <returns></returns> public static int SearchUtilDb( RmsChannelCollection Channels, string strServerUrl, string strDbName, string strFrom, string strKey, out string strXml, out string strError) { strError = ""; strXml = ""; RmsChannel channel = Channels.GetChannel(strServerUrl); if (channel == null) { strError = "get channel error"; return -1; } string[] paths = null; int nRet = SearchPath(channel, strDbName, strFrom, strKey, 1, out paths, out strError); if (nRet == -1) return -1; if (nRet == 0) return 0; string strPath = paths[0]; // 取记录 string strStyle = "content,data,timestamp"; string strMetaData; string strOutputPath; byte[] baTimeStamp = null; long lRet = channel.GetRes(strPath, strStyle, out strXml, out strMetaData, out baTimeStamp, out strOutputPath, out strError); if (lRet == -1) { strError = "检索 '" + strPath + "' 记录体时出错: " + strError; return -1; } return 1; }
// SetEntities() API 恢复动作 /* 日志记录格式 <root> <operation>setEntity</operation> 操作类型 <action>new</action> 具体动作。有new change delete 3种 <style>...</style> 风格。有force nocheckdup noeventlog 3种 <record recPath='中文图书实体/3'><root><parent>2</parent><barcode>0000003</barcode><state>状态2</state><location>阅览室</location><price></price><bookType>教学参考</bookType><registerNo></registerNo><comment>test</comment><mergeComment></mergeComment><batchNo>111</batchNo><borrower></borrower><borrowDate></borrowDate><borrowPeriod></borrowPeriod></root></record> 记录体 <oldRecord recPath='中文图书实体/3'>...</oldRecord> 被覆盖或者删除的记录 动作为change和delete时具备此元素 <operator>test</operator> 操作者 <operTime>Fri, 08 Dec 2006 08:41:46 GMT</operTime> 操作时间 </root> 注:1) 当<action>为delete时,没有<record>元素。为new时,没有<oldRecord>元素。 2) <record>中的内容, 涉及到流通的<borrower><borrowDate><borrowPeriod>等, 在日志恢复阶段, 都应当无效, 这几个内容应当从当前位置库中记录获取, 和<record>中其他内容合并后, 再写入数据库 3) 一次SetEntities()API调用, 可能创建多条日志记录。 * */ // TODO: 要兑现style中force nocheckdup功能 public int RecoverSetEntity( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, out string strError) { strError = ""; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } bool bReuse = false; // 是否能够不顾RecorverLevel状态而重用部分代码 DO_SNAPSHOT: string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); // 快照恢复 if (level == RecoverLevel.Snapshot || bReuse == true) { byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; if (strAction == "new" || strAction == "change" || strAction == "move") { XmlNode node = null; string strRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; return -1; } string strNewRecPath = DomUtil.GetAttr(node, "recPath"); // string strOldRecord = ""; string strOldRecPath = ""; if (strAction == "move") { strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } strOldRecPath = DomUtil.GetAttr(node, "recPath"); } // 写册记录 lRet = channel.DoSaveTextRes(strNewRecPath, strRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入册记录 '" + strNewRecPath + "' 时发生错误: " + strError; return -1; } if (strAction == "move") { // 删除册记录 int nRedoCount = 0; REDO_DELETE: lRet = channel.DoDeleteRes(strOldRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) return 0; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO_DELETE; } } strError = "删除册记录 '" + strOldRecPath + "' 时发生错误: " + strError; return -1; } } } else if (strAction == "delete") { XmlNode node = null; string strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); int nRedoCount = 0; REDO: // 删除册记录 lRet = channel.DoDeleteRes(strRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) return 0; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO; } } strError = "删除册记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } } else { strError = "无法识别的<action>内容 '" + strAction + "'"; return -1; } return 0; } bool bForce = false; bool bNoCheckDup = false; string strStyle = DomUtil.GetElementText(domLog.DocumentElement, "style"); if (StringUtil.IsInList("force", strStyle) == true) bForce = true; if (StringUtil.IsInList("nocheckdup", strStyle) == true) bNoCheckDup = true; // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { // 和数据库中已有记录合并,然后保存 if (strAction == "new" || strAction == "change" || strAction == "move") { XmlNode node = null; string strRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; return -1; } string strNewRecPath = DomUtil.GetAttr(node, "recPath"); // string strOldRecord = ""; string strOldRecPath = ""; if (strAction == "move") { strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } strOldRecPath = DomUtil.GetAttr(node, "recPath"); } // 读出数据库中原有的记录 string strExistXml = ""; string strMetaData = ""; byte[] exist_timestamp = null; string strOutputPath = ""; if ((strAction == "change" || strAction == "move") && bForce == false) // 2008/10/6 { string strSourceRecPath = ""; if (strAction == "change") strSourceRecPath = strNewRecPath; if (strAction == "move") strSourceRecPath = strOldRecPath; lRet = channel.GetRes(strSourceRecPath, out strExistXml, out strMetaData, out exist_timestamp, out strOutputPath, out strError); if (lRet == -1) { // 容错 if (channel.ErrorCode == ChannelErrorCode.NotFound && level == RecoverLevel.LogicAndSnapshot) { // 如果记录不存在, 则构造一条空的记录 // bExist = false; strExistXml = "<root />"; exist_timestamp = null; } else { strError = "在读入原有记录 '"+strNewRecPath+"' 时失败: " + strError; goto ERROR1; } } } // // 把两个记录装入DOM XmlDocument domExist = new XmlDocument(); XmlDocument domNew = new XmlDocument(); try { // 防范空记录 if (String.IsNullOrEmpty(strExistXml) == true) strExistXml = "<root />"; domExist.LoadXml(strExistXml); } catch (Exception ex) { strError = "strExistXml装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } try { domNew.LoadXml(strRecord); } catch (Exception ex) { strError = "strRecord装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 合并新旧记录 string strNewXml = ""; if (bForce == false) { nRet = MergeTwoEntityXml(domExist, domNew, out strNewXml, out strError); if (nRet == -1) goto ERROR1; } else { strNewXml = domNew.OuterXml; } // 保存新记录 byte[] output_timestamp = null; if (strAction == "move") { // 复制源记录到目标位置,然后自动删除源记录 // 但是尚未在目标位置写入最新内容 lRet = channel.DoCopyRecord(strOldRecPath, strNewRecPath, true, // bDeleteSourceRecord out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; exist_timestamp = output_timestamp; // 及时更新时间戳 } lRet = channel.DoSaveTextRes(strNewRecPath, strNewXml, false, // include preamble? "content,ignorechecktimestamp", exist_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; /* if (strAction == "move") { // 删除册记录 int nRedoCount = 0; byte[] timestamp = null; REDO_DELETE: lRet = channel.DoDeleteRes(strOldRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) return 0; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO_DELETE; } } strError = "删除册记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } } * */ } else if (strAction == "delete") { // 和SnapShot方式相同 bReuse = true; goto DO_SNAPSHOT; } else { strError = "无法识别的<action>内容 '" + strAction + "'"; return -1; } } // 容错恢复 if (level == RecoverLevel.Robust) { if (strAction == "move") { strError = "暂不支持SetEntity的move恢复操作"; return -1; } // 和数据库中已有记录合并,然后保存 if (strAction == "change" || strAction == "new") { XmlNode node = null; string strRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; return -1; } // 取得日志记录中声称的新记录路径。不能轻易相信这个路径。 string strNewRecPath = DomUtil.GetAttr(node, "recPath"); // string strOldRecord = ""; string strOldRecPath = ""; string strOldItemBarcode = ""; string strNewItemBarcode = ""; string strExistXml = ""; byte[] exist_timestamp = null; // 日志记录中记载的旧记录体 strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { if (strAction == "change") { strError = "日志记录中缺<oldRecord>元素"; return -1; } } // 日志记录中声称的旧记录路径。不能轻易相信这个路径。 if (node != null) strOldRecPath = DomUtil.GetAttr(node, "recPath"); // 从日志记录中记载的旧记录体中,获得旧记录册条码号 if (String.IsNullOrEmpty(strOldRecord) == false) { nRet = GetItemBarcode(strOldRecord, out strOldItemBarcode, out strError); } nRet = GetItemBarcode(strRecord, out strNewItemBarcode, out strError); // TODO: 需要检查新旧记录中,<barcode>是否一致?如果不一致,则需要对新条码号进行查重? if (strAction == "new" && strOldItemBarcode == "") { if (String.IsNullOrEmpty(strNewItemBarcode) == true) { strError = "因为拟新创建的记录内容中没有包含册条码号,所以new操作被放弃"; return -1; } strOldItemBarcode = strNewItemBarcode; } // 如果有旧记录的册条码号,则需要从数据库中提取最新鲜的旧记录 // (如果没有旧记录的册条码号,则依日志记录中的旧记录) if (String.IsNullOrEmpty(strOldItemBarcode) == false) { string strOutputItemRecPath = ""; // 从册条码号获得册记录 List<string> aPath = null; // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( // Channels, channel, strOldItemBarcode, out strExistXml, 100, out aPath, out exist_timestamp, out strError); if (nRet == 0 || nRet == -1) { if (strAction == "change") { /* // 从库中没有找到,只好依日志记录中记载的旧记录 strExistXml = strOldRecord; * */ strExistXml = ""; // 需要创建一条新记录。strOldRecPath中的路径似乎也可以用,但是要严格检查这个路径是否已经存在记录 -- 只能在这里位置不存在记录时才能用。既然如此麻烦,那就不如纯粹用一个新位置 strOutputItemRecPath = ResPath.GetDbName(strOldRecPath) + "/?"; } else { Debug.Assert(strAction == "new", ""); strExistXml = ""; strOutputItemRecPath = ResPath.GetDbName(strNewRecPath) + "/?"; } } else { // 找到一条或者多条旧记录 Debug.Assert(aPath != null && aPath.Count >= 1, ""); bool bNeedReload = false; if (aPath.Count == 1) { Debug.Assert(nRet == 1, ""); strOutputItemRecPath = aPath[0]; // 是否需要重新装载? bNeedReload = false; // 所取得的第一个路径,其记录已经装载 } else { // 多条 Debug.Assert(aPath.Count > 1, ""); /// // 建议根据strOldRecPath来进行挑选 if (String.IsNullOrEmpty(strOldRecPath) == true) { // 空,无法挑选 // 容错! strOutputItemRecPath = aPath[0]; // 是否需要重新装载? bNeedReload = false; // 所取得的第一个路径,其记录已经装载 } else { ///// nRet = aPath.IndexOf(strOldRecPath); if (nRet != -1) { // 选中 strOutputItemRecPath = aPath[nRet]; // 是否需要重新装载? if (nRet != 0) bNeedReload = true; // 第一个以外的路径才需要装载 } else { // 没有选中,只好依第一个 // 容错 strOutputItemRecPath = aPath[0]; // 是否需要重新装载? bNeedReload = false; // 所取得的第一个路径,其记录已经装载 } } /// } // 重新装载 if (bNeedReload == true) { string strMetaData = ""; lRet = channel.GetRes(strOutputItemRecPath, out strExistXml, out strMetaData, out exist_timestamp, out strOutputItemRecPath, out strError); if (lRet == -1) { strError = "根据strOutputItemRecPath '" + strOutputItemRecPath + "' 重新获得册记录失败: " + strError; return -1; } // 需要检查记录中的<barcode>元素值是否匹配册条码号 } } // 修正strOldRecPath if (strOutputItemRecPath != "") strOldRecPath = strOutputItemRecPath; else strOldRecPath = ""; // 破坏掉,以免后面被用 strNewRecPath = strOutputItemRecPath; } // end if 如果有旧记录的册条码号 else { // (如果没有旧记录的册条码号,则依日志记录中的旧记录) // 但无法确定旧记录的路径。也就无法确定覆盖位置。因此建议放弃这种特定的“修改操作”。 strError = "因为日志记录中没有记载旧记录条码号,因此无法确定记录位置,因此change操作被放弃"; return -1; } if (strAction == "change") { if (strNewItemBarcode != "" && strNewItemBarcode != strOldItemBarcode) { // 新旧记录的条码号不一致,需要对新条码号进行查重 List<string> aPath = null; string strTempXml = ""; byte[] temp_timestamp = null; // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( // Channels, channel, strNewItemBarcode, out strTempXml, 100, out aPath, out temp_timestamp, out strError); if (nRet > 0) { // 有重复,取其第一条,作为老记录进行合并,并保存回这条的位置 strNewRecPath = aPath[0]; exist_timestamp = temp_timestamp; strExistXml = strTempXml; } } } // 把两个记录装入DOM XmlDocument domExist = new XmlDocument(); XmlDocument domNew = new XmlDocument(); try { // 防范空记录 if (String.IsNullOrEmpty(strExistXml) == true) strExistXml = "<root />"; domExist.LoadXml(strExistXml); } catch (Exception ex) { strError = "strExistXml装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } try { domNew.LoadXml(strRecord); } catch (Exception ex) { strError = "strRecord装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 合并新旧记录 string strNewXml = ""; if (bForce == false) { nRet = MergeTwoEntityXml(domExist, domNew, out strNewXml, out strError); if (nRet == -1) goto ERROR1; } else { strNewXml = domNew.OuterXml; } // 保存新记录 byte[] output_timestamp = null; string strOutputPath = ""; if (strAction == "move") { // 复制源记录到目标位置,然后自动删除源记录 // 但是尚未在目标位置写入最新内容 lRet = channel.DoCopyRecord(strOldRecPath, strNewRecPath, true, // bDeleteSourceRecord out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; exist_timestamp = output_timestamp; // 及时更新时间戳 } /* // 测试 { string strRecID = ResPath.GetRecordId(strNewRecPath); if (strRecID != "?") { try { long id = Convert.ToInt64(strRecID); if (id > 150848) { Debug.Assert(false, "id超过尾部"); } } catch { } } } * */ lRet = channel.DoSaveTextRes(strNewRecPath, strNewXml, false, // include preamble? "content,ignorechecktimestamp", exist_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } else if (strAction == "delete") { XmlNode node = null; string strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); string strOldItemBarcode = ""; nRet = GetItemBarcode(strOldRecord, out strOldItemBarcode, out strError); if (String.IsNullOrEmpty(strOldItemBarcode) == true) { strError = "因为日志记录中的旧记录中缺乏非空的<barcode>内容,所以无法进行依据条码号定位的删除,delete操作被放弃"; return -1; } string strOutputItemRecPath = ""; string strExistXml = ""; byte[] exist_timestamp = null; // 从册条码号获得册记录 List<string> aPath = null; // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( // Channels, channel, strOldItemBarcode, out strExistXml, 100, out aPath, out exist_timestamp, out strError); if (nRet == -1) return -1; if (nRet == 0) { // 本来就不存在 return 0; } if (nRet >= 1) { /// // 找到一条或者多条旧记录 Debug.Assert(aPath != null && aPath.Count >= 1, ""); bool bNeedReload = false; if (aPath.Count == 1) { Debug.Assert(nRet == 1, ""); /* strOutputItemRecPath = aPath[0]; // 是否需要重新装载? bNeedReload = false; // 所取得的第一个路径,其记录已经装载 * */ strError = "册条码号 " + strOldItemBarcode + " 目前仅有唯一一条记录,放弃删除"; return -1; } else { // 多条 Debug.Assert(aPath.Count > 1, ""); /// // 建议根据strRecPath来进行挑选 if (String.IsNullOrEmpty(strRecPath) == true) { strError = "册条码号 '" + strOldItemBarcode + "' 命中 " + aPath.Count.ToString() + " 条记录,而<oldRecord>的recPath参数缺乏,因此无法进行精确删除,delete操作被放弃"; return -1; } else { ///// nRet = aPath.IndexOf(strRecPath); if (nRet != -1) { // 选中 strOutputItemRecPath = aPath[nRet]; // 是否需要重新装载? if (nRet != 0) bNeedReload = true; // 第一个以外的路径才需要装载 } else { strError = "册条码号 '" + strOldItemBarcode + "' 命中 " + aPath.Count.ToString() + " 条记录,虽用了(<oldRecord>元素中属性recPath的)确认路径 '" + strRecPath + "' 也无法确认出其中一条,无法精确删除,因此delete操作被放弃"; return -1; } } } /// // 重新装载 if (bNeedReload == true) { string strMetaData = ""; lRet = channel.GetRes(strOutputItemRecPath, out strExistXml, out strMetaData, out exist_timestamp, out strOutputItemRecPath, out strError); if (lRet == -1) { strError = "根据strOutputItemRecPath '" + strOutputItemRecPath + "' 重新获得册记录失败: " + strError; return -1; } // 需要检查记录中的<barcode>元素值是否匹配册条码号 } } // 把两个记录装入DOM XmlDocument domExist = new XmlDocument(); try { // 防范空记录 if (String.IsNullOrEmpty(strExistXml) == true) strExistXml = "<root />"; domExist.LoadXml(strExistXml); } catch (Exception ex) { strError = "strExistXml装载进入DOM时发生错误: " + ex.Message; return -1; } string strDetail = ""; bool bHasCirculationInfo = IsEntityHasCirculationInfo(domExist, out strDetail); // 观察已经存在的记录是否有流通信息 if (bHasCirculationInfo == true && bForce == false) { strError = "拟删除的册记录 '" + strOutputItemRecPath + "' 中包含有流通信息("+strDetail+"),不能删除。"; goto ERROR1; } int nRedoCount = 0; byte[] timestamp = exist_timestamp; byte[] output_timestamp = null; REDO: // 删除册记录 lRet = channel.DoDeleteRes(strOutputItemRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) return 0; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO; } } strError = "删除册记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } } else { strError = "无法识别的<action>内容 '" + strAction + "'"; return -1; } } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
/* <root> <operation>writeRes</operation> <requestResPath>...</requestResPath> 资源路径参数。也就是请求API是的strResPath参数值。可能在路径中的记录ID部分包含问号,表示要追加创建新的记录 <resPath>...</resPath> 资源路径。资源的确定路径。 <ranges>...</ranges> 字节范围 <totalLength>...</totalLength> 总长度 <metadata>...</metadata> 此元素的文本即是记录体,但注意为不透明的字符串(HtmlEncoding后的记录字符串)。 <style>...</style> 当 style 中包含 delete 子串时表示要删除这个资源 <operator>test</operator> <operTime>Fri, 08 Dec 2006 10:12:20 GMT</operTime> </root> * 可能会有一个attachment * * */ public int RecoverWriteRes( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, Stream attachmentLog, out string strError) { strError = ""; // 暂时把Robust当作Logic处理 if (level == RecoverLevel.Robust) level = RecoverLevel.Logic; long lRet = 0; // int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } bool bReuse = false; // 是否能够不顾RecorverLevel状态而重用部分代码 DO_SNAPSHOT: // 快照恢复 if (level == RecoverLevel.Snapshot || bReuse == true) { string strResPath = DomUtil.GetElementText( domLog.DocumentElement, "resPath"); if (string.IsNullOrEmpty(strResPath) == true) { strError = "日志记录中缺<resPath>元素"; return -1; } string strRanges = DomUtil.GetElementText( domLog.DocumentElement, "ranges"); if (string.IsNullOrEmpty(strRanges) == true) { strError = "日志记录中缺<ranges>元素"; return -1; } string strTotalLength = DomUtil.GetElementText( domLog.DocumentElement, "totalLength"); if (string.IsNullOrEmpty(strTotalLength) == true) { strError = "日志记录中缺<totalLength>元素"; return -1; } long lTotalLength = 0; try { lTotalLength = Convert.ToInt64(strTotalLength); } catch { strError = "lTotalLength值 '"+strTotalLength+"' 格式不正确"; return -1; } string strMetadata = DomUtil.GetElementText( domLog.DocumentElement, "metadata"); string strStyle = DomUtil.GetElementText( domLog.DocumentElement, "style"); // 读入记录内容 byte[] baRecord = null; if (attachmentLog != null && attachmentLog.Length > 0) { baRecord = new byte[(int)attachmentLog.Length]; attachmentLog.Seek(0, SeekOrigin.Begin); attachmentLog.Read(baRecord, 0, (int)attachmentLog.Length); } strStyle += ",ignorechecktimestamp"; byte[] timestamp = null; string strOutputResPath = ""; byte[] output_timestamp = null; if (StringUtil.IsInList("delete", strStyle) == true) { // 2015/9/3 增加 lRet = channel.DoDeleteRes(strResPath, timestamp, strStyle, out output_timestamp, out strError); } else { lRet = channel.WriteRes(strResPath, strRanges, lTotalLength, baRecord, strMetadata, strStyle, timestamp, out strOutputResPath, out output_timestamp, out strError); } if (lRet == -1) { strError = "WriteRes() '" + strResPath + "' 时发生错误: " + strError; return -1; } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { // 和SnapShot方式相同 bReuse = true; goto DO_SNAPSHOT; } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
// SetComments() API 恢复动作 /* 日志记录格式 <root> <operation>setComment</operation> 操作类型 <action>new</action> 具体动作。有new change delete 3种 <style>...</style> 风格。有force nocheckdup noeventlog 3种 <record recPath='中文图书评注/3'>...</record> 记录体 <oldRecord recPath='中文图书评注/3'>...</oldRecord> 被覆盖或者删除的记录 动作为change和delete时具备此元素 <operator>test</operator> 操作者 <operTime>Fri, 08 Dec 2006 08:41:46 GMT</operTime> 操作时间 </root> 注:1) 当<action>为delete时,没有<record>元素。为new时,没有<oldRecord>元素。 2) 一次SetComments()API调用, 可能创建多条日志记录。 * */ // TODO: 要兑现style中force nocheckdup功能 public int RecoverSetComment( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, out string strError) { strError = ""; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } bool bReuse = false; // 是否能够不顾RecorverLevel状态而重用部分代码 DO_SNAPSHOT: string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); // 快照恢复 if (level == RecoverLevel.Snapshot || bReuse == true) { byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; if (strAction == "new" || strAction == "change" || strAction == "move") { XmlNode node = null; string strRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; return -1; } string strNewRecPath = DomUtil.GetAttr(node, "recPath"); // string strOldRecord = ""; string strOldRecPath = ""; if (strAction == "move") { strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } strOldRecPath = DomUtil.GetAttr(node, "recPath"); } // 写评注记录 lRet = channel.DoSaveTextRes(strNewRecPath, strRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入评注记录 '" + strNewRecPath + "' 时发生错误: " + strError; return -1; } if (strAction == "move") { // 删除评注记录 int nRedoCount = 0; REDO_DELETE: lRet = channel.DoDeleteRes(strOldRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) return 0; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO_DELETE; } } strError = "删除评注记录 '" + strOldRecPath + "' 时发生错误: " + strError; return -1; } } } else if (strAction == "delete") { XmlNode node = null; string strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); int nRedoCount = 0; REDO: // 删除评注记录 lRet = channel.DoDeleteRes(strRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) return 0; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO; } } strError = "删除评注记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } } else { strError = "无法识别的<action>内容 '" + strAction + "'"; return -1; } return 0; } bool bForce = false; bool bNoCheckDup = false; string strStyle = DomUtil.GetElementText(domLog.DocumentElement, "style"); if (StringUtil.IsInList("force", strStyle) == true) bForce = true; if (StringUtil.IsInList("nocheckdup", strStyle) == true) bNoCheckDup = true; // 逻辑恢复或者混合恢复或者容错恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot || level == RecoverLevel.Robust) // 容错恢复没有单独实现 { // 和数据库中已有记录合并,然后保存 if (strAction == "new" || strAction == "change" || strAction == "move") { XmlNode node = null; string strRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; return -1; } string strNewRecPath = DomUtil.GetAttr(node, "recPath"); // string strOldRecord = ""; string strOldRecPath = ""; if (strAction == "move") { strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } strOldRecPath = DomUtil.GetAttr(node, "recPath"); } // 读出数据库中原有的记录 string strExistXml = ""; string strMetaData = ""; byte[] exist_timestamp = null; string strOutputPath = ""; if ((strAction == "change" || strAction == "move") && bForce == false) { string strSourceRecPath = ""; if (strAction == "change") strSourceRecPath = strNewRecPath; if (strAction == "move") strSourceRecPath = strOldRecPath; lRet = channel.GetRes(strSourceRecPath, out strExistXml, out strMetaData, out exist_timestamp, out strOutputPath, out strError); if (lRet == -1) { // 容错 if (channel.ErrorCode == ChannelErrorCode.NotFound && level == RecoverLevel.LogicAndSnapshot) { // 如果记录不存在, 则构造一条空的记录 // bExist = false; strExistXml = "<root />"; exist_timestamp = null; } else { strError = "在读入原有记录 '" + strNewRecPath + "' 时失败: " + strError; goto ERROR1; } } } // // 把两个记录装入DOM XmlDocument domExist = new XmlDocument(); XmlDocument domNew = new XmlDocument(); try { // 防范空记录 if (String.IsNullOrEmpty(strExistXml) == true) strExistXml = "<root />"; domExist.LoadXml(strExistXml); } catch (Exception ex) { strError = "strExistXml装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } try { domNew.LoadXml(strRecord); } catch (Exception ex) { strError = "strRecord装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 合并新旧记录 string strNewXml = ""; if (bForce == false) { nRet = this.CommentItemDatabase.MergeTwoItemXml( null, domExist, domNew, out strNewXml, out strError); if (nRet == -1) goto ERROR1; } else { strNewXml = domNew.OuterXml; } // 保存新记录 byte[] output_timestamp = null; if (strAction == "move") { // 复制源记录到目标位置,然后自动删除源记录 // 但是尚未在目标位置写入最新内容 lRet = channel.DoCopyRecord(strOldRecPath, strNewRecPath, true, // bDeleteSourceRecord out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; exist_timestamp = output_timestamp; // 及时更新时间戳 } lRet = channel.DoSaveTextRes(strNewRecPath, strNewXml, false, // include preamble? "content,ignorechecktimestamp", exist_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } else if (strAction == "delete") { // 和SnapShot方式相同 bReuse = true; goto DO_SNAPSHOT; } else { strError = "无法识别的<action>内容 '" + strAction + "'"; return -1; } } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
// 删除应用服务器在dp2Kernel内核中创建的数据库 // parameters: // strXmlFileName library.xml 文件的全路径 // return: // -1 出错 // 0 用户放弃删除 // 1 已经删除 public static int DeleteKernelDatabases( IWin32Window owner, string strInstanceName, string strXmlFilename, out string strError) { strError = ""; int nRet = 0; DialogResult result = MessageBox.Show(owner == null ? ForegroundWindow.Instance : owner, "是否要删除应用服务器实例 '" + strInstanceName + "' 在数据库内核中创建过的全部数据库?\r\n\r\n(注:如果现在不删除,将来也可以用内核管理(dp2manager)工具进行删除)", "安装 dp2Library", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result == DialogResult.No) return 0; XmlDocument dom = new XmlDocument(); try { dom.Load(strXmlFilename); } catch (Exception ex) { strError = "XML文件 '" + strXmlFilename + "' 装载到DOM时发生错误: " + ex.Message; return -1; } XmlNode rmsserver_node = dom.DocumentElement.SelectSingleNode("rmsserver"); if (rmsserver_node == null) { strError = "<rmsserver>元素没有找到"; return -1; } string strKernelUrl = DomUtil.GetAttr(rmsserver_node, "url"); if (String.IsNullOrEmpty(strKernelUrl) == true) { strError = "<rmsserver>元素的url属性为空"; return -1; } using (RmsChannelCollection channels = new RmsChannelCollection()) { RmsChannel channel = channels.GetChannel(strKernelUrl); if (channel == null) { strError = "channel == null"; return -1; } string strUserName = DomUtil.GetAttr(rmsserver_node, "username"); string strPassword = DomUtil.GetAttr(rmsserver_node, "password"); string EncryptKey = "dp2circulationpassword"; try { strPassword = Cryptography.Decrypt( strPassword, EncryptKey); } catch { strError = "<rmsserver>元素password属性中的密码设置不正确"; return -1; } nRet = channel.Login(strUserName, strPassword, out strError); if (nRet == -1) { strError = "以用户名 '" + strUserName + "' 和密码登录内核时失败: " + strError; return -1; } nRet = DeleteAllDatabase( channel, dom, out strError); if (nRet == -1) return -1; return 1; } }
// ChangeReaderPassword() API 恢复动作 /* <root> <operation>changeReaderPassword</operation> <readerBarcode>...</readerBarcode> 读者证条码号 <newPassword>5npAUJ67/y3aOvdC0r+Dj7SeXGE=</newPassword> <operator>test</operator> <operTime>Fri, 08 Dec 2006 09:01:38 GMT</operTime> <readerRecord recPath='...'>...</readerRecord> 最新读者记录 </root> * */ public int RecoverChangeReaderPassword( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, out string strError) { strError = ""; // 暂时把Robust当作Logic处理 if (level == RecoverLevel.Robust) level = RecoverLevel.Logic; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } DO_SNAPSHOT: // 快照恢复 if (level == RecoverLevel.Snapshot) { XmlNode node = null; string strReaderXml = DomUtil.GetElementText(domLog.DocumentElement, "readerRecord", out node); if (node == null) { strError = "日志记录中缺<readerRecord>元素"; return -1; } string strReaderRecPath = DomUtil.GetAttr(node, "recPath"); byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; // 写读者记录 lRet = channel.DoSaveTextRes(strReaderRecPath, strReaderXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入读者记录 '" + strReaderRecPath + "' 时发生错误: " + strError; return -1; } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { // 读出原有读者记录,修改密码后存回 string strReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "readerBarcode"); if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "日志记录中缺乏<readerBarcode>元素"; goto ERROR1; } string strNewPassword = DomUtil.GetElementText(domLog.DocumentElement, "newPassword"); if (String.IsNullOrEmpty(strNewPassword) == true) { strError = "日志记录中缺乏<newPassword>元素"; goto ERROR1; } // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入证条码号为 '" + strReaderBarcode + "' 的读者记录时发生错误: " + strError; goto ERROR1; } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // strNewPassword中本来就是SHA1形态 DomUtil.SetElementText(readerdom.DocumentElement, "password", strNewPassword); byte[] output_timestamp = null; string strOutputPath = ""; // 写回读者记录 lRet = channel.DoSaveTextRes(strOutputReaderRecPath, readerdom.OuterXml, false, "content,ignorechecktimestamp", reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
// 检测管理用户是否已经存在? // return: // -1 出错 // 0 不存在 // 1 存在, 且密码一致 // 2 存在, 但密码不一致 int DetectManageUser(out string strError) { strError = ""; if (this.textBox_kernelUrl.Text == "") { strError = "尚未指定dp2Kernel服务器URL"; return -1; } if (this.textBox_manageUserName.Text == "") { strError = "尚未指定代理帐户的用户名"; return -1; } if (this.textBox_managePassword.Text != this.textBox_confirmManagePassword.Text) { strError = "代理帐户 密码 和 再次输入密码 不一致。请重新输入。"; return -1; } RmsChannelCollection channels = new RmsChannelCollection(); RmsChannel channel = channels.GetChannel(this.textBox_kernelUrl.Text); if (channel == null) { strError = "channel == null"; return -1; } // Debug.Assert(false, ""); int nRet = channel.Login(this.textBox_manageUserName.Text, this.textBox_managePassword.Text, out strError); if (nRet == -1) { strError = "以用户名 '" + this.textBox_manageUserName.Text + "' 和密码登录失败: " + strError; return -1; } channel.DoLogout(out strError); if (nRet == 0) { channels.AskAccountInfo -= new AskAccountInfoEventHandle(channels_AskAccountInfo); channels.AskAccountInfo += new AskAccountInfoEventHandle(channels_AskAccountInfo); nRet = channel.UiLogin("为确认代理帐户是否存在, 请用root用户身份登录。", "", LoginStyle.None, out strError); if (nRet == -1 || nRet == 0) { strError = "以root用户身份登录失败: " + strError + "\r\n\r\n因此无法确定代理帐户是否存在"; return -1; } string strRecPath = ""; string strXml = ""; byte[] baTimeStamp = null; // 获得用户记录 // return: // -1 error // 0 not found // >=1 检索命中的条数 nRet = GetUserRecord( channel, this.textBox_manageUserName.Text, out strRecPath, out strXml, out baTimeStamp, out strError); if (nRet == -1) { strError = "获取用户 '" + this.textBox_manageUserName.Text + "' 信息时发生错误: " + strError + "\r\n\r\n因此无法确定代理帐户是否存在。"; return -1; } if (nRet == 1) { strError = "代理帐户 '" + this.textBox_manageUserName.Text + "' 已经存在, 但其密码和当前面板拟设置的密码不一致。"; return 2; } if (nRet >= 1) { strError = "以 '" + this.textBox_manageUserName.Text + "' 为用户名 的用户记录存在多条,这是一个严重错误,请利用root身份启用dp2manager尽快修正此错误。"; return -1; } strError = "代理帐户 '" + this.textBox_manageUserName.Text + "' 不存在。"; return 0; } strError = "代理帐户 '" + this.textBox_manageUserName.Text + "' 代理帐户经检验存在。"; return 1; }
// SetReaderInfo() API 恢复动作 /* <root> <operation>setReaderInfo</operation> 操作类型 <action>...</action> 具体动作。有new change delete move 4种 <record recPath='...'>...</record> 新记录 <oldRecord recPath='...'>...</oldRecord> 被覆盖或者删除的记录 动作为 change 和 delete 时具备此元素 <changedEntityRecord itemBarcode='...' recPath='...' oldBorrower='...' newBorrower='...' /> 若干个元素。表示连带发生修改的册记录 <operator>test</operator> 操作者 <operTime>Fri, 08 Dec 2006 09:01:38 GMT</operTime> 操作时间 </root> 注: new 的时候只有<record>元素,delete的时候只有<oldRecord>元素,change的时候两者都有 * */ public int RecoverSetReaderInfo( RmsChannelCollection Channels, RecoverLevel level_param, XmlDocument domLog, out string strError) { strError = ""; string[] element_names = reader_element_names; RecoverLevel level = level_param; // 暂时把Robust当作Logic处理 if (level == RecoverLevel.Robust) level = RecoverLevel.Logic; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } bool bReuse = false; // 是否能够不顾RecorverLevel状态而重用部分代码 DO_SNAPSHOT: string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); // 快照恢复 if (level == RecoverLevel.Snapshot || bReuse == true) { byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; if (strAction == "new" || strAction == "change") { XmlNode node = null; string strRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; return -1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); // 写读者记录 lRet = channel.DoSaveTextRes(strRecPath, strRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入读者记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } // 2015/9/11 XmlNodeList nodes = domLog.DocumentElement.SelectNodes("changedEntityRecord"); foreach(XmlElement item in nodes) { string strItemBarcode = item.GetAttribute("itemBarcode"); string strItemRecPath = item.GetAttribute("recPath"); string strOldReaderBarcode = item.GetAttribute("oldBorrower"); string strNewReaderBarcode = item.GetAttribute("newBorrower"); // 修改一条册记录,的 borrower 元素内容 // parameters: // -2 保存记录时出错 // -1 一般性错误 // 0 成功 nRet = ChangeBorrower( channel, strItemBarcode, strItemRecPath, strOldReaderBarcode, strNewReaderBarcode, true, out strError); if (nRet == -1 || nRet == -2) { strError = "修改读者记录所关联的在借册记录时出错:" + strError; return -1; } } } else if (strAction == "delete") { XmlNode node = null; string strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); int nRedoCount = 0; REDO: // 删除读者记录 lRet = channel.DoDeleteRes(strRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) return 0; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO; } } strError = "删除读者记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } } else if (strAction == "move") { XmlNode node = null; string strRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; return -1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); if (string.IsNullOrEmpty(strRecPath) == true) { strError = "日志记录中<record>元素内缺recPath属性值"; return -1; } string strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } string strOldRecPath = DomUtil.GetAttr(node, "recPath"); if (string.IsNullOrEmpty(strOldRecPath) == true) { strError = "日志记录中<oldRecord>元素内缺recPath属性值"; return -1; } /* int nRedoCount = 0; REDO: * */ // 移动读者记录 lRet = channel.DoCopyRecord( strOldRecPath, strRecPath, true, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { // 源记录本来就不存在。进行容错处理 if (channel.ErrorCode == ChannelErrorCode.NotFound && level_param == RecoverLevel.Robust) { // 优先用最新的记录内容复原。实在没有才用旧的记录内容 if (string.IsNullOrEmpty(strRecord) == true) strRecord = strOldRecord; if (string.IsNullOrEmpty(strRecord) == false) { // 写读者记录 lRet = channel.DoSaveTextRes(strRecPath, strRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "为容错,写入读者记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } return 0; } } strError = "移动读者记录 '" + strOldRecPath + "' 到 '" + strRecPath + "' 时发生错误: " + strError; return -1; } // <record>中如果有记录体,则还需要写入一次 // 所以这里需要注意,在创建日志记录的时候,如果没有在CopyRecord()后追加修改过记录,则不要创建<record>记录正文部分,以免引起多余的日志恢复时写入动作 if (string.IsNullOrEmpty(strRecord) == false) { lRet = channel.DoSaveTextRes(strRecPath, strRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入读者记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } } } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { // 和数据库中已有记录合并,然后保存 if (strAction == "new" || strAction == "change") { XmlNode node = null; string strRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; return -1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); // 读出数据库中原有的记录 string strExistXml = ""; string strMetaData = ""; byte[] exist_timestamp = null; string strOutputPath = ""; if (strAction == "change") { lRet = channel.GetRes(strRecPath, out strExistXml, out strMetaData, out exist_timestamp, out strOutputPath, out strError); if (lRet == -1) { // 容错 if (channel.ErrorCode == ChannelErrorCode.NotFound && level == RecoverLevel.LogicAndSnapshot) { // 如果记录不存在, 则构造一条空的记录 // bExist = false; strExistXml = "<root />"; exist_timestamp = null; } else { strError = "在读入原有记录 '" + strRecPath + "' 时失败: " + strError; goto ERROR1; } } } // // 把两个记录装入DOM XmlDocument domExist = new XmlDocument(); XmlDocument domNew = new XmlDocument(); try { // 防范空记录 if (String.IsNullOrEmpty(strExistXml) == true) strExistXml = "<root />"; domExist.LoadXml(strExistXml); } catch (Exception ex) { strError = "strExistXml装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } try { domNew.LoadXml(strRecord); } catch (Exception ex) { strError = "strRecord装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 合并新旧记录 string strNewXml = ""; nRet = MergeTwoReaderXml( element_names, "change", domExist, domNew, out strNewXml, out strError); if (nRet == -1) goto ERROR1; // 保存新记录 byte[] output_timestamp = null; lRet = channel.DoSaveTextRes(strRecPath, strNewXml, false, // include preamble? "content,ignorechecktimestamp", exist_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { goto ERROR1; } } else if (strAction == "delete") { // 和SnapShot方式相同 bReuse = true; goto DO_SNAPSHOT; } else if (strAction == "move") { // 和SnapShot方式相同 bReuse = true; goto DO_SNAPSHOT; } else { strError = "无法识别的<action>内容 '" + strAction + "'"; return -1; } } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
// 检索文章 // return: // -1 error // 其他 命中数 public int Search( string strServerUrl, string strQueryXml, RmsChannelCollection Channels, string strLang, out string strError) { strError = ""; string strMessage = ""; // 加写锁 this.m_lock.AcquireWriterLock(m_nLockTimeout); try { this.File.Clear(); // 清空集合 //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; RmsChannel channel = Channels.GetChannel(strServerUrl); Debug.Assert(channel != null, "Channels.GetChannel 异常"); strMessage += "--- begin search ...\r\n"; DateTime time = DateTime.Now; //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; long nRet = channel.DoSearch(strQueryXml, "default", "", // strOuputStyle out strError); if (nRet == -1) { strError = "检索时出错: " + strError; return -1; } TimeSpan delta = DateTime.Now - time; strMessage += "search end. time="+delta.ToString()+"\r\n"; if (nRet == 0) return 0; // not found long lTotalCount = nRet; //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; strMessage += "--- begin get search result ...\r\n"; time = DateTime.Now; long lStart = 0; long lPerCount = Math.Min(lTotalCount, 1000); for(;;) { //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; List<string> aPath = null; lPerCount = Math.Min((lTotalCount - lStart), 1000); nRet = channel.DoGetSearchResult( "default", lStart, lPerCount, strLang, null, // stop, out aPath, out strError); if (nRet == -1) { strError = "检索库时出错: " + strError; return -1; } delta = DateTime.Now - time; strMessage += "get search result end. time="+delta.ToString()+"\r\n"; if (aPath.Count == 0) { strError = "检索库时获取的检索结果为空"; return -1; } //if (page.Response.IsClientConnected == false) // 灵敏中断 // return -1; strMessage += "--- begin build storage ...\r\n"; time = DateTime.Now; int i; // 加入新行对象。新行对象中,只初始化了m_strRecID参数 for(i=0;i<aPath.Count;i++) { ClientRecordItem item = new ClientRecordItem(); item.Path = (string)aPath[i]; this.File.Add(item); if ((i % 100) == 0) { strMessage += "process " + Convert.ToString(i)+ "\r\n"; } } delta = DateTime.Now - time; strMessage += "build storage end. time="+delta.ToString()+"\r\n"; lStart += aPath.Count; if (lStart >= lTotalCount) break; } return 1; } finally { this.m_lock.ReleaseWriterLock(); } }
// Borrow() API 恢复动作 /* 日志记录格式如下 <root> <operation>borrow</operation> 操作类型 <readerBarcode>R0000002</readerBarcode> 读者证条码号 <itemBarcode>0000001</itemBarcode> 册条码号 <borrowDate>Fri, 08 Dec 2006 04:17:31 GMT</borrowDate> 借阅日期 <borrowPeriod>30day</borrowPeriod> 借阅期限 <no>0</no> 续借次数。0为首次普通借阅,1开始为续借 <operator>test</operator> 操作者 <operTime>Fri, 08 Dec 2006 04:17:31 GMT</operTime> 操作时间 <confirmItemRecPath>...</confirmItemRecPath> 辅助判断用的册记录路径 <readerRecord recPath='...'>...</readerRecord> 最新读者记录 <itemRecord recPath='...'>...</itemRecord> 最新册记录 </root> * */ // parameters: // bForce 是否为容错状态。在容错状态下,如果遇到重复的册条码号,就算做第一条。 public int RecoverBorrow( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, bool bForce, out string strError) { strError = ""; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } DO_SNAPSHOT: // 快照恢复 if (level == RecoverLevel.Snapshot) { XmlNode node = null; string strReaderXml = DomUtil.GetElementText(domLog.DocumentElement, "readerRecord", out node); if (node == null) { strError = "日志记录中缺<readerRecord>元素"; return -1; } string strReaderRecPath = DomUtil.GetAttr(node, "recPath"); string strItemXml = DomUtil.GetElementText(domLog.DocumentElement, "itemRecord", out node); if (node == null) { strError = "日志记录中缺<itemRecord>元素"; return -1; } string strItemRecPath = DomUtil.GetAttr(node, "recPath"); byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; // 写读者记录 lRet = channel.DoSaveTextRes(strReaderRecPath, strReaderXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入读者记录 '" + strReaderRecPath + "' 时发生错误: " + strError; return -1; } // 写册记录 lRet = channel.DoSaveTextRes(strItemRecPath, strItemXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入册记录 '" + strItemRecPath + "' 时发生错误: " + strError; return -1; } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { string strRecoverComment = ""; string strReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "readerBarcode"); if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "<readerBarcode>元素值为空"; goto ERROR1; } // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入证条码号为 '" + strReaderBarcode + "' 的读者记录时发生错误: " + strError; goto ERROR1; } string strLibraryCode = ""; // 获得读者库的馆代码 // return: // -1 出错 // 0 成功 nRet = GetLibraryCode( strOutputReaderRecPath, out strLibraryCode, out strError); if (nRet == -1) goto ERROR1; XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // 读入册记录 string strConfirmItemRecPath = DomUtil.GetElementText(domLog.DocumentElement, "confirmItemRecPath"); string strItemBarcode = DomUtil.GetElementText(domLog.DocumentElement, "itemBarcode"); if (String.IsNullOrEmpty(strItemBarcode) == true) { strError = "<strItemBarcode>元素值为空"; goto ERROR1; } string strItemXml = ""; string strOutputItemRecPath = ""; byte[] item_timestamp = null; // 如果已经有确定的册记录路径 if (String.IsNullOrEmpty(strConfirmItemRecPath) == false) { string strMetaData = ""; lRet = channel.GetRes(strConfirmItemRecPath, out strItemXml, out strMetaData, out item_timestamp, out strOutputItemRecPath, out strError); if (lRet == -1) { strError = "根据strConfirmItemRecPath '" + strConfirmItemRecPath + "' 获得册记录失败: " + strError; goto ERROR1; } // 需要检查记录中的<barcode>元素值是否匹配册条码号 // TODO: 如果记录路径所表达的记录不存在,或者其<barcode>元素值和要求的册条码号不匹配,那么都要改用逻辑方法,也就是利用册条码号来获得记录。 // 当然,这种情况下,非常要紧的是确保数据库的素质很好,本身没有重条码号的情况出现。 } else { // 从册条码号获得册记录 List<string> aPath = null; // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( // Channels, channel, strItemBarcode, out strItemXml, 100, out aPath, out item_timestamp, out strError); if (nRet == 0) { strError = "册条码号 '" + strItemBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入册条码号为 '" + strItemBarcode + "' 的册记录时发生错误: " + strError; goto ERROR1; } if (aPath.Count > 1) { if (bForce == true) { // 容错! strOutputItemRecPath = aPath[0]; strRecoverComment += "册条码号 " + strItemBarcode + " 有 " + aPath.Count.ToString() + " 条重复记录,因受容错要求所迫,权且采用其中第一个记录 " + strOutputItemRecPath + " 来进行借阅操作。"; } else { strError = "册条码号为 '" + strItemBarcode + "' 的册记录有 " + aPath.Count.ToString() + " 条,但此时comfirmItemRecPath却为空"; goto ERROR1; } } else { Debug.Assert(nRet == 1, ""); Debug.Assert(aPath.Count == 1, ""); if (nRet == 1) { strOutputItemRecPath = aPath[0]; } } } XmlDocument itemdom = null; nRet = LibraryApplication.LoadToDom(strItemXml, out itemdom, out strError); if (nRet == -1) { strError = "装载册记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // 修改读者记录 // 修改册记录 // TODO: 容错情况下如果遇到册条码号是重复的,要写入额外的日志。 nRet = BorrowChangeReaderAndItemRecord( // Channels, channel, strItemBarcode, strReaderBarcode, domLog, strRecoverComment, strLibraryCode, ref readerdom, ref itemdom, out strError); if (nRet == -1) goto ERROR1; // 写回读者、册记录 byte[] output_timestamp = null; string strOutputPath = ""; // 写回读者记录 lRet = channel.DoSaveTextRes(strOutputReaderRecPath, readerdom.OuterXml, false, "content,ignorechecktimestamp", reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; // 写回册记录 lRet = channel.DoSaveTextRes(strOutputItemRecPath, itemdom.OuterXml, false, "content,ignorechecktimestamp", item_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } // 容错恢复 if (level == RecoverLevel.Robust) { string strRecoverComment = ""; string strReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "readerBarcode"); if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "<readerBarcode>元素值为空"; return -1; } // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; // TODO: 记入信息文件 // 从日志记录中获得读者记录 XmlNode node = null; strReaderXml = DomUtil.GetElementText(domLog.DocumentElement, "readerRecord", out node); if (node == null) { strError = "日志记录中缺<readerRecord>元素"; return -1; } string strReaderRecPath = DomUtil.GetAttr(node, "recPath"); if (String.IsNullOrEmpty(strReaderRecPath) == true) { strError = "日志记录中<readerRecord>元素缺recPath属性"; return -1; } // 新增一条读者记录 strOutputReaderRecPath = ResPath.GetDbName(strReaderRecPath) + "/?"; reader_timestamp = null; } else { if (nRet == -1) { strError = "读入证条码号为 '" + strReaderBarcode + "' 的读者记录时发生错误: " + strError; return -1; } } string strLibraryCode = ""; // 获得读者库的馆代码 // return: // -1 出错 // 0 成功 nRet = GetLibraryCode( strOutputReaderRecPath, out strLibraryCode, out strError); if (nRet == -1) goto ERROR1; XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; return -1; } // 读入册记录 string strConfirmItemRecPath = DomUtil.GetElementText(domLog.DocumentElement, "confirmItemRecPath"); string strItemBarcode = DomUtil.GetElementText(domLog.DocumentElement, "itemBarcode"); if (String.IsNullOrEmpty(strItemBarcode) == true) { strError = "<strItemBarcode>元素值为空"; return -1; } string strItemXml = ""; string strOutputItemRecPath = ""; byte[] item_timestamp = null; // 从册条码号获得册记录 List<string> aPath = null; // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( // Channels, channel, strItemBarcode, out strItemXml, 100, out aPath, out item_timestamp, out strError); if (nRet == 0) { strError = "册条码号 '" + strItemBarcode + "' 不存在"; // TODO: 记入信息文件 XmlNode node = null; strItemXml = DomUtil.GetElementText(domLog.DocumentElement, "itemRecord", out node); if (node == null) { strError = "日志记录中缺<itemRecord>元素"; return -1; } string strItemRecPath = DomUtil.GetAttr(node, "recPath"); if (String.IsNullOrEmpty(strItemRecPath) == true) { strError = "日志记录中<itemRecord>元素缺recPath属性"; return -1; } // 新增一条册记录 strOutputItemRecPath = ResPath.GetDbName(strItemRecPath) + "/?"; item_timestamp = null; } else { if (nRet == -1) { strError = "读入册条码号为 '" + strItemBarcode + "' 的册记录时发生错误: " + strError; return -1; } Debug.Assert(aPath != null, ""); bool bNeedReload = false; if (aPath.Count > 1) { // 建议根据strConfirmItemRecPath来进行挑选 if (String.IsNullOrEmpty(strConfirmItemRecPath) == true) { // 容错! strOutputItemRecPath = aPath[0]; strRecoverComment += "册条码号 " + strItemBarcode + " 有 " + aPath.Count.ToString() + " 条重复记录,因受容错要求所迫,权且采用其中第一个记录 " + strOutputItemRecPath + " 来进行借阅操作。"; // 是否需要重新装载? bNeedReload = false; // 所取得的第一个路径,其记录已经装载 } else { ///// nRet = aPath.IndexOf(strConfirmItemRecPath); if (nRet != -1) { strOutputItemRecPath = aPath[nRet]; strRecoverComment += "册条码号 " + strItemBarcode + " 有 " + aPath.Count.ToString() + " 条重复记录,经过找到strConfirmItemRecPath=[" + strConfirmItemRecPath + "]" + "来进行借阅操作。"; // 是否需要重新装载? if (nRet != 0) bNeedReload = true; // 第一个以外的路径才需要装载 } else { // 容错 strOutputItemRecPath = aPath[0]; strRecoverComment += "册条码号 " + strItemBarcode + " 有 " + aPath.Count.ToString() + " 条重复记录,在其中无法找到strConfirmItemRecPath=[" + strConfirmItemRecPath + "]的记录" + "因受容错要求所迫,权且采用其中第一个记录 " + strOutputItemRecPath + " 来进行借阅操作。"; // 是否需要重新装载? bNeedReload = false; // 所取得的第一个路径,其记录已经装载 /* strError = "册条码号 " + strItemBarcode + " 有 " + aPath.Count.ToString() + " 条重复记录,在其中无法找到strConfirmItemRecPath=[" + strConfirmItemRecPath + "]的记录"; return -1; * */ } } } // if (aPath.Count > 1) else { Debug.Assert(nRet == 1, ""); Debug.Assert(aPath.Count == 1, ""); if (nRet == 1) { strOutputItemRecPath = aPath[0]; // 是否需要重新装载? bNeedReload = false; // 所取得的第一个路径,其记录已经装载 } } // 重新装载 if (bNeedReload == true) { string strMetaData = ""; lRet = channel.GetRes(strOutputItemRecPath, out strItemXml, out strMetaData, out item_timestamp, out strOutputItemRecPath, out strError); if (lRet == -1) { strError = "根据strOutputItemRecPath '" + strOutputItemRecPath + "' 重新获得册记录失败: " + strError; return -1; } // 需要检查记录中的<barcode>元素值是否匹配册条码号 } } //// XmlDocument itemdom = null; nRet = LibraryApplication.LoadToDom(strItemXml, out itemdom, out strError); if (nRet == -1) { strError = "装载册记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // 修改读者记录 // 修改册记录 nRet = BorrowChangeReaderAndItemRecord( // Channels, channel, strItemBarcode, strReaderBarcode, domLog, strRecoverComment, strLibraryCode, ref readerdom, ref itemdom, out strError); if (nRet == -1) goto ERROR1; // 写回读者、册记录 byte[] output_timestamp = null; string strOutputPath = ""; // 写回读者记录 lRet = channel.DoSaveTextRes(strOutputReaderRecPath, readerdom.OuterXml, false, "content,ignorechecktimestamp", reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; // 写回册记录 lRet = channel.DoSaveTextRes(strOutputItemRecPath, itemdom.OuterXml, false, "content,ignorechecktimestamp", item_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
// 刷新数据库定义 // parameters: // strDatabaseInfo 要刷新的下属文件特性。<refreshStyle include="keys,browse" exclude="">(表示只刷新keys和browse两个重要配置文件)或者<refreshStyle include="*" exclude="template">(表示刷新全部文件,但是不要刷新template) 如果参数值为空,表示全部刷新 // strOutputInfo 返回keys定义发生改变的数据库名。"<keysChanged dbpaths='http://*****:*****@biblioDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的书目库(biblioDbName属性)相关<database>元素没有找到"; goto ERROR1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新书目库的定义"; goto ERROR1; } string strSyntax = DomUtil.GetAttr(nodeDatabase, "syntax"); if (String.IsNullOrEmpty(strSyntax) == true) strSyntax = "unimarc"; string strUsage = ""; string strIssueDbName = DomUtil.GetAttr(nodeDatabase, "issueDbName"); if (String.IsNullOrEmpty(strIssueDbName) == true) strUsage = "book"; else strUsage = "series"; // 刷新书目库 string strTemplateDir = this.DataDir + "\\templates\\" + "biblio_" + strSyntax + "_" + strUsage; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新小书目库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); // 刷新实体库 string strEntityDbName = DomUtil.GetAttr(nodeDatabase, "name"); if (String.IsNullOrEmpty(strEntityDbName) == false) { strTemplateDir = this.DataDir + "\\templates\\" + "item"; nRet = RefreshDatabase(channel, strTemplateDir, strEntityDbName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新书目库 '" + strName + "' 所从属的实体库 '" + strEntityDbName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strEntityDbName); } // 刷新订购库 string strOrderDbName = DomUtil.GetAttr(nodeDatabase, "orderDbName"); if (String.IsNullOrEmpty(strOrderDbName) == false) { strTemplateDir = this.DataDir + "\\templates\\" + "order"; nRet = RefreshDatabase(channel, strTemplateDir, strOrderDbName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新书目库 '" + strName + "' 所从属的订购库 '" + strOrderDbName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strOrderDbName); } // 刷新期库 if (String.IsNullOrEmpty(strIssueDbName) == false) { strTemplateDir = this.DataDir + "\\templates\\" + "issue"; nRet = RefreshDatabase(channel, strTemplateDir, strIssueDbName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新书目库 '" + strName + "' 所从属的期库 '" + strIssueDbName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strIssueDbName); } // 刷新评注库 string strCommentDbName = DomUtil.GetAttr(nodeDatabase, "commentDbName"); if (String.IsNullOrEmpty(strCommentDbName) == false) { strTemplateDir = this.DataDir + "\\templates\\" + "comment"; nRet = RefreshDatabase(channel, strTemplateDir, strCommentDbName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新书目库 '" + strName + "' 所从属的评注库 '" + strCommentDbName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strCommentDbName); } continue; } // 单独刷新实体库 if (this.IsItemDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的实体库(name属性)相关<database>元素没有找到"; goto ERROR1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新实体库的定义"; goto ERROR1; } // 刷新实体库 string strTemplateDir = this.DataDir + "\\templates\\" + "item"; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新实体库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } // 单独刷新订购库 if (this.IsOrderDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@orderDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的订购库(orderDbName属性)相关<database>元素没有找到"; goto ERROR1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新订购库的定义"; goto ERROR1; } // 刷新订购库 string strTemplateDir = this.DataDir + "\\templates\\" + "order"; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新订购库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } // 单独刷新期库 if (this.IsIssueDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@issueDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的期库(issueDbName属性)相关<database>元素没有找到"; goto ERROR1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新期库的定义"; goto ERROR1; } // 刷新期库 string strTemplateDir = this.DataDir + "\\templates\\" + "issue"; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新期库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } // 单独刷新评注库 if (this.IsCommentDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@commentDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的评注库(commentDbName属性)相关<database>元素没有找到"; goto ERROR1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新评注库的定义"; goto ERROR1; } // 刷新评注库 string strTemplateDir = this.DataDir + "\\templates\\" + "comment"; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新评注库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } // 刷新读者库 if (this.IsReaderDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("readerdbgroup/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的读者库(name属性)相关<database>元素没有找到"; goto ERROR1; } // 2012/9/9 // 分馆用户只允许刷新属于管辖分馆的读者库 if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { string strExistLibraryCode = DomUtil.GetAttr(nodeDatabase, "libraryCode"); if (string.IsNullOrEmpty(strExistLibraryCode) == true || StringUtil.IsInList(strExistLibraryCode, strLibraryCodeList) == false) { strError = "刷新读者库 '" + strName + "' 定义被拒绝。当前用户只能刷新图书馆代码完全完全属于 '" + strLibraryCodeList + "' 范围的读者库定义"; goto ERROR1; } } // 刷新读者库 string strTemplateDir = this.DataDir + "\\templates\\" + "reader"; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新读者库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } // 刷新预约到书库 if (this.ArrivedDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新预约到书库的定义"; goto ERROR1; } // 刷新预约到书库 string strTemplateDir = this.DataDir + "\\templates\\" + "arrived"; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新预约到书库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } // 刷新违约金库 if (this.AmerceDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新违约金库的定义"; goto ERROR1; } // 刷新违约金库 string strTemplateDir = this.DataDir + "\\templates\\" + "amerce"; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新违约金库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } // 刷新发票库 if (this.InvoiceDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新发票库的定义"; goto ERROR1; } // 刷新发票库 string strTemplateDir = this.DataDir + "\\templates\\" + "invoice"; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新发票库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } // 刷新消息库 if (this.MessageDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新消息库的定义"; goto ERROR1; } // 刷新消息库 string strTemplateDir = this.DataDir + "\\templates\\" + "message"; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新消息库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } // 刷新实用库 if (IsUtilDbName(strName) == true) { XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("utilDb/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "不存在name属性值为 '" + strName + "' 的<utilDb/database>的元素"; goto ERROR1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许刷新实用库的定义"; goto ERROR1; } string strType = DomUtil.GetAttr(nodeDatabase, "type").ToLower(); // 刷新实用库 string strTemplateDir = this.DataDir + "\\templates\\" + strType; nRet = RefreshDatabase(channel, strTemplateDir, strName, strInclude, strExclude, out strError); if (nRet == -1) { strError = "刷新实用库 '" + strName + "' 定义时发生错误: " + strError; goto ERROR1; } if (nRet == 1) keyschanged_dbnames.Add(strName); continue; } strError = "数据库名 '" + strName + "' 不属于 dp2library 目前管辖的范围..."; goto ERROR1; } // 2015/6/13 if (keyschanged_dbnames.Count > 0) { nRet = InitialKdbs( Channels, out strError); if (nRet == -1) return -1; // 重新初始化虚拟库定义 this.vdbs = null; nRet = this.InitialVdbs(Channels, out strError); if (nRet == -1) return -1; } if (bAutoRebuildKeys == true && keyschanged_dbnames.Count > 0) { nRet = StartRebuildKeysTask(StringUtil.MakePathList(keyschanged_dbnames, ","), out strError); if (nRet == -1) return -1; } { // 增加WebServiceUrl部分 for (int i = 0; i < keyschanged_dbnames.Count; i++) { keyschanged_dbnames[i] = this.WsUrl.ToLower() + "?" + keyschanged_dbnames[i]; } XmlDocument dom = new XmlDocument(); dom.LoadXml("<keysChanged />"); DomUtil.SetAttr(dom.DocumentElement, "dbpaths", StringUtil.MakePathList(keyschanged_dbnames, ";")); strOutputInfo = dom.OuterXml; } return 0; ERROR1: if (keyschanged_dbnames.Count > 0) { // 增加WebServiceUrl部分 for (int i = 0; i < keyschanged_dbnames.Count; i++) { keyschanged_dbnames[i] = this.WsUrl.ToLower() + "?" + keyschanged_dbnames[i]; } XmlDocument dom = new XmlDocument(); dom.LoadXml("<keysChanged />"); DomUtil.SetAttr(dom.DocumentElement, "dbpaths", StringUtil.MakePathList(keyschanged_dbnames, ";")); strOutputInfo = dom.OuterXml; } return -1; }
// Amerce() API 恢复动作 /* <root> <operation>amerce</operation> 操作类型 <action>amerce</action> 具体动作。有amerce undo modifyprice <readerBarcode>...</readerBarcode> 读者证条码号 <!-- <idList>...<idList> ID列表,逗号间隔 已废止 --> <amerceItems> <amerceItem id="..." newPrice="..." newComment="..." /> newComment中内容追加或替换原来的注释内容。到底是追加还是覆盖,取决于第一个字符是否为'>'还是'<',前者为追加(这时第一个字符不被当作内容)。如果第一个字符不是这两者之一,则默认为追加 ... </amerceItems> <amerceRecord recPath='...'><root><itemBarcode>0000001</itemBarcode><readerBarcode>R0000002</readerBarcode><state>amerced</state><id>632958375041543888-1</id><over>31day</over><borrowDate>Sat, 07 Oct 2006 09:04:28 GMT</borrowDate><borrowPeriod>30day</borrowPeriod><returnDate>Thu, 07 Dec 2006 09:04:27 GMT</returnDate><returnOperator>test</returnOperator></root></amerceRecord> 在罚款库中创建的新记录。注意<amerceRecord>元素可以重复。<amerceRecord>元素内容里面的<itemBarcode><readerBarcode><id>等具备了足够的信息。 <operator>test</operator> 操作者 <operTime>Fri, 08 Dec 2006 10:09:36 GMT</operTime> 操作时间 <readerRecord recPath='...'>...</readerRecord> 最新读者记录 </root> <root> <operation>amerce</operation> <action>undo</action> <readerBarcode>...</readerBarcode> 读者证条码号 <!-- <idList>...<idList> ID列表,逗号间隔 已废止 --> <amerceItems> <amerceItem id="..." newPrice="..."/> ... </amerceItems> <amerceRecord recPath='...'><root><itemBarcode>0000001</itemBarcode><readerBarcode>R0000002</readerBarcode><state>amerced</state><id>632958375041543888-1</id><over>31day</over><borrowDate>Sat, 07 Oct 2006 09:04:28 GMT</borrowDate><borrowPeriod>30day</borrowPeriod><returnDate>Thu, 07 Dec 2006 09:04:27 GMT</returnDate><returnOperator>test</returnOperator></root></amerceRecord> Undo所去掉的罚款库记录 <operator>test</operator> <operTime>Fri, 08 Dec 2006 10:12:20 GMT</operTime> <readerRecord recPath='...'>...</readerRecord> 最新读者记录 </root> <root> <operation>amerce</operation> <action>modifyprice</action> <readerBarcode>...</readerBarcode> 读者证条码号 <amerceItems> <amerceItem id="..." newPrice="..." newComment="..."/> newComment中内容追加或替换原来的注释内容。到底是追加还是覆盖,取决于第一个字符是否为'>'还是'<',前者为追加(这时第一个字符不被当作内容)。如果第一个字符不是这两者之一,则默认为追加 ... </amerceItems> <!-- modifyprice操作时不产生<amerceRecord>元素 --> <operator>test</operator> <operTime>Fri, 08 Dec 2006 10:12:20 GMT</operTime> <oldReaderRecord recPath='...'>...</oldReaderRecord> 操作前旧的读者记录。<oldReaderRecord>元素是modifyprice操作时特有的元素 <readerRecord recPath='...'>...</readerRecord> 最新读者记录 </root> 2007/12/18 <root> <operation>amerce</operation> 操作类型 <action>expire</action> 以停代金到期 <readerBarcode>...</readerBarcode> 读者证条码号 <expiredOverdues> 已经到期的若干<overdue>元素 <overdue ... /> ... </expiredOverdues> <operator>test</operator> 操作者 如果为#readersMonitor,表示为后台线程 <operTime>Fri, 08 Dec 2006 10:09:36 GMT</operTime> 操作时间 <readerRecord recPath='...'>...</readerRecord> 最新读者记录 </root> * 2008/6/20 <root> <operation>amerce</operation> <action>modifycomment</action> <readerBarcode>...</readerBarcode> 读者证条码号 <amerceItems> <amerceItem id="..." newComment="..."/> newComment中内容追加或替换原来的注释内容。到底是追加还是覆盖,取决于第一个字符是否为'>'还是'<',前者为追加(这时第一个字符不被当作内容)。如果第一个字符不是这两者之一,则默认为追加 ... </amerceItems> <!-- modifycomment操作时不产生<amerceRecord>元素 --> <operator>test</operator> <operTime>Fri, 08 Dec 2006 10:12:20 GMT</operTime> <oldReaderRecord recPath='...'>...</oldReaderRecord> 操作前旧的读者记录。<oldReaderRecord>元素是modifycomment操作时特有的元素 <readerRecord recPath='...'>...</readerRecord> 最新读者记录 </root> * * * */ public int RecoverAmerce( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, out string strError) { strError = ""; // 暂时把Robust当作Logic处理 if (level == RecoverLevel.Robust) level = RecoverLevel.Logic; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } DO_SNAPSHOT: string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); // 快照恢复 if (level == RecoverLevel.Snapshot) { byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; if (strAction == "amerce") { XmlNodeList nodes = domLog.DocumentElement.SelectNodes("amerceRecord"); int nErrorCount = 0; for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strRecord = node.InnerText; string strRecPath = DomUtil.GetAttr(node, "recPath"); // 写违约金记录 string strError0 = ""; lRet = channel.DoSaveTextRes(strRecPath, strRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError0); if (lRet == -1) { // 继续循环 if (strError != "") strError += "\r\n"; strError += "写入违约金记录 '" + strRecPath + "' 时发生错误: " + strError0; nErrorCount++; } } if (nErrorCount > 0) return -1; } else if (strAction == "undo") { XmlNodeList nodes = domLog.DocumentElement.SelectNodes("amerceRecord"); int nErrorCount = 0; for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strRecPath = DomUtil.GetAttr(node, "recPath"); int nRedoCount = 0; string strError0 = ""; REDO: // 删除违约金记录 lRet = channel.DoDeleteRes(strRecPath, timestamp, out output_timestamp, out strError0); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO; } } // 继续循环 if (strError != "") strError += "\r\n"; strError += "删除违约金记录 '" + strRecPath + "' 时发生错误: " + strError0; nErrorCount++; } } // end of for if (nErrorCount > 0) return -1; } else if (strAction == "modifyprice") { // 这里什么都不作,只等后面用快照的读者记录来恢复 } else if (strAction == "expire") { // 这里什么都不作,只等后面用快照的读者记录来恢复 } else if (strAction == "modifycomment") { // 这里什么都不作,只等后面用快照的读者记录来恢复 } else if (strAction == "appendcomment") { // 这里什么都不作,只等后面用快照的读者记录来恢复 } else { strError = "未知的<action>类型: " + strAction; return -1; } { XmlNode node = null; // 写入读者记录 string strReaderRecord = DomUtil.GetElementText(domLog.DocumentElement, "readerRecord", out node); string strReaderRecPath = DomUtil.GetAttr(node, "recPath"); // 写读者记录 lRet = channel.DoSaveTextRes(strReaderRecPath, strReaderRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入读者记录 '" + strReaderRecPath + "' 时发生错误: " + strError; return -1; } } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { string strReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "readerBarcode"); if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "日志记录中缺乏<readerBarcode>元素"; return -1; } string strLibraryCode = DomUtil.GetElementText(domLog.DocumentElement, "libraryCode"); string strOperator = DomUtil.GetElementText(domLog.DocumentElement, "operator"); string strOperTime = DomUtil.GetElementText(domLog.DocumentElement, "operTime"); /* string strAmerceItemIdList = DomUtil.GetElementText(domLog.DocumentElement, "idList"); if (String.IsNullOrEmpty(strAmerceItemIdList) == true) { strError = "日志记录中缺乏<idList>元素"; return -1; } * */ AmerceItem[] amerce_items = ReadAmerceItemList(domLog); // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入读者记录时发生错误: " + strError; goto ERROR1; } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } byte[] output_timestamp = null; string strOutputPath = ""; if (strAction == "amerce") { List<string> NotFoundIds = null; List<string> Ids = null; List<string> AmerceRecordXmls = null; // 交违约金:在读者记录中去除所选的<overdue>元素,并且构造一批新记录准备加入违约金库 // return: // -1 error // 0 读者dom没有变化 // 1 读者dom发生了变化 nRet = DoAmerceReaderXml( strLibraryCode, ref readerdom, amerce_items, strOperator, strOperTime, out AmerceRecordXmls, out NotFoundIds, out Ids, out strError); if (nRet == -1) { // 在错误信息后面增补每个id对应的amerce record if (NotFoundIds != null && NotFoundIds.Count > 0) { strError += "。读者证条码号为 " + strReaderBarcode + ",日志记录中相关的AmerceRecord如下:\r\n" + GetAmerceRecordStringByID(domLog, NotFoundIds); } goto ERROR1; } // 如果有精力,可以把AmerceRecordXmls和日志记录中的<amerceRecord>逐个进行核对 // 写入违约金记录 XmlNodeList nodes = domLog.DocumentElement.SelectNodes("amerceRecord"); for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strRecord = node.InnerText; string strRecPath = DomUtil.GetAttr(node, "recPath"); // 写违约金记录 lRet = channel.DoSaveTextRes(strRecPath, strRecord, false, "content,ignorechecktimestamp", null, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入违约金记录 '" + strRecPath + "' 时发生错误: " + strError; goto ERROR1; } } } if (strAction == "undo") { XmlNodeList nodes = domLog.DocumentElement.SelectNodes("amerceRecord"); // 看看根下面是否有overdues元素 XmlNode root = readerdom.DocumentElement.SelectSingleNode("overdues"); if (root == null) { root = readerdom.CreateElement("overdues"); readerdom.DocumentElement.AppendChild(root); } for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strRecord = node.InnerText; string strRecPath = DomUtil.GetAttr(node, "recPath"); // 如果有精力,可以把违约金记录中的id和日志记录<amerceItems>中的id对比检查 // 违约金信息加回读者记录 string strTempReaderBarcode = ""; string strOverdueString = ""; // 将违约金记录格式转换为读者记录中的<overdue>元素格式 nRet = ConvertAmerceRecordToOverdueString(strRecord, out strTempReaderBarcode, out strOverdueString, out strError); if (nRet == -1) goto ERROR1; if (strTempReaderBarcode != strReaderBarcode) { strError = "<amerceRecord>中的读者证条码号和日志记录中的<readerBarcode>读者证条码号不一致"; goto ERROR1; } XmlDocumentFragment fragment = readerdom.CreateDocumentFragment(); fragment.InnerXml = strOverdueString; // 2008/11/13 changed XmlNode node_added = root.AppendChild(fragment); Debug.Assert(node_added != null, ""); string strReason = DomUtil.GetAttr(node_added, "reason"); if (strReason == "押金。") { string strPrice = DomUtil.GetAttr(node_added, "price"); if (String.IsNullOrEmpty(strPrice) == false) { // 需要从<foregift>元素中减去这个价格 string strContent = DomUtil.GetElementText(readerdom.DocumentElement, "foregift"); string strNegativePrice = ""; // 将形如"-123.4+10.55-20.3"的价格字符串反转正负号 // parameters: // bSum 是否要顺便汇总? true表示要汇总 nRet = PriceUtil.NegativePrices(strPrice, false, out strNegativePrice, out strError); if (nRet == -1) { strError = "反转价格字符串 '" + strPrice + "时发生错误: " + strError; goto ERROR1; } strContent = PriceUtil.JoinPriceString(strContent, strNegativePrice); DomUtil.SetElementText(readerdom.DocumentElement, "foregift", strContent); // bReaderDomChanged = true; } } // 删除违约金记录 int nRedoCount = 0; byte[] timestamp = null; REDO: // 删除违约金记录 lRet = channel.DoDeleteRes(strRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO; } } // 是否需要继续循环? strError = "删除违约金记录 '" + strRecPath + "' 时发生错误: " + strError; goto ERROR1; } } } if (strAction == "modifyprice") { nRet = ModifyPrice(ref readerdom, amerce_items, out strError); if (nRet == -1) { strError = "ModifyPrice()时发生错误: " + strError; goto ERROR1; } } // 2008/6/20 if (strAction == "modifycomment") { nRet = ModifyComment( ref readerdom, amerce_items, out strError); if (nRet == -1) { strError = "ModifyComment()时发生错误: " + strError; goto ERROR1; } } if (strAction == "expire") { // 寻找<expiredOverdues/overdue>元素 XmlNodeList nodes = domLog.DocumentElement.SelectNodes("//expiredOverdues/overdue"); for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strID = DomUtil.GetAttr(node, "id"); if (String.IsNullOrEmpty(strID) == true) continue; // 从读者记录中去掉这个id的<overdue>元素 XmlNode nodeOverdue = readerdom.DocumentElement.SelectSingleNode("overdues/overdue[@id='"+strID+"']"); if (nodeOverdue != null) { if (nodeOverdue.ParentNode != null) nodeOverdue.ParentNode.RemoveChild(nodeOverdue); } } } // 写回读者记录 strReaderXml = readerdom.OuterXml; lRet = channel.DoSaveTextRes(strOutputReaderRecPath, strReaderXml, false, "content,ignorechecktimestamp", reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
// 初始化数据库 int InitializeDatabase( RmsChannelCollection Channels, string strLibraryCodeList, string strDatabaseNames, out string strOutputInfo, out string strError) { strOutputInfo = ""; strError = ""; int nRet = 0; long lRet = 0; bool bDbNameChanged = false; // 初始化后,检索途径名等都可能被改变 RmsChannel channel = Channels.GetChannel(this.WsUrl); string[] names = strDatabaseNames.Split(new char[] { ',' }); for (int i = 0; i < names.Length; i++) { string strName = names[i].Trim(); if (String.IsNullOrEmpty(strName) == true) continue; // 书目库整体初始化,也是可以的 // TODO: 将来可以考虑单独初始化书目库而不删除组内相关库 if (this.IsBiblioDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@biblioDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的书目库(biblioDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化书目库"; return -1; } // 初始化书目库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化小书目库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; // 初始化实体库 string strEntityDbName = DomUtil.GetAttr(nodeDatabase, "name"); if (String.IsNullOrEmpty(strEntityDbName) == false) { lRet = channel.DoInitialDB(strEntityDbName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化书目库 '" + strName + "' 所从属的实体库 '" + strEntityDbName + "' 时发生错误: " + strError; return -1; } } // 初始化订购库 string strOrderDbName = DomUtil.GetAttr(nodeDatabase, "orderDbName"); if (String.IsNullOrEmpty(strOrderDbName) == false) { lRet = channel.DoInitialDB(strOrderDbName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化书目库 '" + strName + "' 所从属的订购库 '" + strOrderDbName + "' 时发生错误: " + strError; return -1; } } // 初始化期库 string strIssueDbName = DomUtil.GetAttr(nodeDatabase, "issueDbName"); if (String.IsNullOrEmpty(strIssueDbName) == false) { lRet = channel.DoInitialDB(strIssueDbName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化书目库 '" + strName + "' 所从属的期库 '" + strIssueDbName + "' 时发生错误: " + strError; return -1; } } // 初始化评注库 string strCommentDbName = DomUtil.GetAttr(nodeDatabase, "commentDbName"); if (String.IsNullOrEmpty(strCommentDbName) == false) { lRet = channel.DoInitialDB(strCommentDbName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化书目库 '" + strName + "' 所从属的评注库 '" + strCommentDbName + "' 时发生错误: " + strError; return -1; } } continue; } // 单独初始化实体库 if (this.IsItemDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的实体库(name属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化实体库"; return -1; } // 初始化实体库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化实体库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; continue; } // 单独初始化订购库 if (this.IsOrderDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@orderDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的订购库(orderDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化订购库"; return -1; } // 初始化订购库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化订购库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; continue; } // 单独初始化期库 if (this.IsIssueDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@issueDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的期库(issueDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化期库"; return -1; } // 初始化期库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化期库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; continue; } // 单独初始化评注库 if (this.IsCommentDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup/database[@commentDbName='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的评注库(commentDbName属性)相关<database>元素没有找到"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化评注库"; return -1; } // 初始化评注库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化评注库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; continue; } // 初始化读者库 if (this.IsReaderDbName(strName) == true) { // 获得相关配置小节 XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("readerdbgroup/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "配置DOM中名字为 '" + strName + "' 的读者库(name属性)相关<database>元素没有找到"; return -1; } // 2012/9/9 // 分馆用户只允许初始化属于管辖分馆的读者库 if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { string strExistLibraryCode = DomUtil.GetAttr(nodeDatabase, "libraryCode"); if (string.IsNullOrEmpty(strExistLibraryCode) == true || StringUtil.IsInList(strExistLibraryCode, strLibraryCodeList) == false) { strError = "初始化读者库 '" + strName + "' 被拒绝。当前用户只能初始化图书馆代码完全完全属于 '" + strLibraryCodeList + "' 范围的读者库"; return -1; } } // 初始化读者库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化读者库 '" + strName + "' 时发生错误: " + strError; return -1; } bDbNameChanged = true; continue; } // 初始化预约到书库 if (this.ArrivedDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化预约到书库"; return -1; } // 初始化预约到书库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化预约到书库 '" + strName + "' 时发生错误: " + strError; return -1; } continue; } // 初始化违约金库 if (this.AmerceDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化违约金库"; return -1; } // 初始化违约金库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化违约金库 '" + strName + "' 时发生错误: " + strError; return -1; } continue; } // 初始化发票库 if (this.InvoiceDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化发票库"; return -1; } // 初始化发票库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化发票库 '" + strName + "' 时发生错误: " + strError; return -1; } continue; } // 初始化消息库 if (this.MessageDbName == strName) { if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化消息库"; return -1; } // 初始化消息库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化消息库 '" + strName + "' 时发生错误: " + strError; return -1; } continue; } // 初始化实用库 if (IsUtilDbName(strName) == true) { XmlNode nodeDatabase = this.LibraryCfgDom.DocumentElement.SelectSingleNode("utilDb/database[@name='" + strName + "']"); if (nodeDatabase == null) { strError = "不存在name属性值为 '" + strName + "' 的<utilDb/database>的元素"; return -1; } if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false) { strError = "当前用户不是全局用户,不允许初始化实用库"; return -1; } // 初始化实用库 lRet = channel.DoInitialDB(strName, out strError); if (lRet == -1 && channel.ErrorCode != ChannelErrorCode.NotFound) { strError = "初始化实用库 '" + strName + "' 时发生错误: " + strError; return -1; } continue; } strError = "数据库名 '" + strName + "' 不属于 dp2library 目前管辖的范围..."; return -1; } if (bDbNameChanged == true) { nRet = InitialKdbs( Channels, out strError); if (nRet == -1) return -1; /* // 重新初始化虚拟库定义 this.vdbs = null; nRet = this.InitialVdbs(Channels, out strError); if (nRet == -1) return -1; * */ } return 0; }
/* <root> <operation>devolveReaderInfo</operation> <sourceReaderBarcode>...</sourceReaderBarcode> 源读者证条码号 <targetReaderBarcode>...</targetReaderBarcode> 目标读者证条码号 <borrows>...</borrows> 移动过去的<borrows>内容,下级为<borrow>元素 <overdues>...</overdues> 移动过去的<overdue>内容,下级为<overdue>元素 <sourceReaderRecord recPath='...'>...</sourceReaderRecord> 最新源读者记录 <targetReaderRecord recPath='...'>...</targetReaderRecord> 最新目标读者记录 <changedEntityRecord recPath='...' attahchmentIndex='.'>...</changedEntityRecord> 所牵连到的发生了修改的实体记录。此元素的文本即是记录体,但注意为不透明的字符串(HtmlEncoding后的记录字符串)。如果存在attachmentIndex属性,则表明实体记录不在此元素文本中,而在日志记录的附件中 <operator>test</operator> <operTime>Fri, 08 Dec 2006 10:12:20 GMT</operTime> </root> * * */ public int RecoverDevolveReaderInfo( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, Stream attachmentLog, out string strError) { strError = ""; // 暂时把Robust当作Logic处理 if (level == RecoverLevel.Robust) level = RecoverLevel.Logic; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } DO_SNAPSHOT: // 快照恢复 if (level == RecoverLevel.Snapshot) { /* // 观察是否有<warning>元素 XmlNode nodeWarning = domLog.SelectSingleNode("warning"); if (nodeWarning != null) { // 如果<warning元素存在,表明只能采用逻辑恢复> strError = nodeWarning.InnerText; return -1; } */ // 获源读者记录 XmlNode node = null; string strSourceReaderXml = DomUtil.GetElementText( domLog.DocumentElement, "sourceReaderRecord", out node); if (node == null) { strError = "日志记录中缺<sourceReaderRecord>元素"; return -1; } string strSourceReaderRecPath = DomUtil.GetAttr(node, "recPath"); byte[] timestamp = null; string strOutputPath = ""; byte[] output_timestamp = null; // 写源读者记录 lRet = channel.DoSaveTextRes(strSourceReaderRecPath, strSourceReaderXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入源读者记录 '" + strSourceReaderRecPath + "' 时发生错误: " + strError; return -1; } // 获目标读者记录 node = null; string strTargetReaderXml = DomUtil.GetElementText( domLog.DocumentElement, "targetReaderRecord", out node); if (node == null) { strError = "日志记录中缺<targetReaderRecord>元素"; return -1; } string strTargetReaderRecPath = DomUtil.GetAttr(node, "recPath"); // 写目标读者记录 lRet = channel.DoSaveTextRes(strTargetReaderRecPath, strTargetReaderXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入目标读者记录 '" + strSourceReaderRecPath + "' 时发生错误: " + strError; return -1; } // 循环,写入相关的若干实体记录 XmlNodeList nodeEntities = domLog.DocumentElement.SelectNodes("changedEntityRecord"); for (int i = 0; i < nodeEntities.Count; i++) { XmlNode nodeEntity = nodeEntities[i]; string strItemRecPath = DomUtil.GetAttr(nodeEntity, "recPath"); string strAttachmentIndex = DomUtil.GetAttr(nodeEntity, "attachmentIndex"); string strItemXml = ""; if (String.IsNullOrEmpty(strAttachmentIndex) == true) { strItemXml = nodeEntity.InnerText; if (String.IsNullOrEmpty(strItemXml) == true) { strError = "<changedEntityRecord>元素缺乏文本内容。"; return -1; } } else { // 实体记录在附件中 int nAttachmentIndex = 0; try { nAttachmentIndex = Convert.ToInt32(strAttachmentIndex); } catch { strError = "<changedEntityRecord>元素的attachmentIndex属性值'"+strAttachmentIndex+"'格式不正确,应当为>=0的纯数字"; return -1; } byte[] baItem = null; nRet = GetAttachmentRecord( attachmentLog, nAttachmentIndex, out baItem, out strError); if (nRet == -1) { strError = "获得 index 为 "+nAttachmentIndex.ToString()+" 的日志附件记录时出错:" + strError; return -1; } strItemXml = Encoding.UTF8.GetString(baItem); } // 写册记录 lRet = channel.DoSaveTextRes(strItemRecPath, strItemXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入册记录 '" + strItemRecPath + "' 时发生错误: " + strError; return -1; } } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { string strOperTimeString = DomUtil.GetElementText(domLog.DocumentElement, "operTime"); string strSourceReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "sourceReaderBarcode"); if (String.IsNullOrEmpty(strSourceReaderBarcode) == true) { strError = "<sourceReaderBarcode>元素值为空"; goto ERROR1; } string strTargetReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "targetReaderBarcode"); if (String.IsNullOrEmpty(strTargetReaderBarcode) == true) { strError = "<targetReaderBarcode>元素值为空"; goto ERROR1; } // 读入源读者记录 string strSourceReaderXml = ""; string strSourceOutputReaderRecPath = ""; byte[] source_reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strSourceReaderBarcode, out strSourceReaderXml, out strSourceOutputReaderRecPath, out source_reader_timestamp, out strError); if (nRet == 0) { strError = "源读者证条码号 '" + strSourceReaderBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入证条码号为 '" + strSourceReaderBarcode + "' 的源读者记录时发生错误: " + strError; goto ERROR1; } XmlDocument source_readerdom = null; nRet = LibraryApplication.LoadToDom(strSourceReaderXml, out source_readerdom, out strError); if (nRet == -1) { strError = "装载源读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // // 读入目标读者记录 string strTargetReaderXml = ""; string strTargetOutputReaderRecPath = ""; byte[] target_reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strTargetReaderBarcode, out strTargetReaderXml, out strTargetOutputReaderRecPath, out target_reader_timestamp, out strError); if (nRet == 0) { strError = "目标读者证条码号 '" + strTargetReaderBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入证条码号为 '" + strTargetReaderBarcode + "' 的目标读者记录时发生错误: " + strError; goto ERROR1; } XmlDocument target_readerdom = null; nRet = LibraryApplication.LoadToDom(strTargetReaderXml, out target_readerdom, out strError); if (nRet == -1) { strError = "装载目标读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } Stream tempstream = null; // 移动信息 XmlDocument domTemp = null; // 移动借阅信息 -- <borrows>元素内容 // return: // -1 error // 0 not found brrowinfo // 1 found and moved nRet = DevolveBorrowInfo( // Channels, channel, strSourceReaderBarcode, strTargetReaderBarcode, strOperTimeString, ref source_readerdom, ref target_readerdom, ref domTemp, "", out tempstream, out strError); if (nRet == -1) goto ERROR1; // 移动超期违约金信息 -- <overdues>元素内容 // return: // -1 error // 0 not found overdueinfo // 1 found and moved nRet = DevolveOverdueInfo( strSourceReaderBarcode, strTargetReaderBarcode, strOperTimeString, ref source_readerdom, ref target_readerdom, ref domTemp, out strError); if (nRet == -1) goto ERROR1; // 写回读者记录 byte[] output_timestamp = null; string strOutputPath = ""; // 写回源读者记录 lRet = channel.DoSaveTextRes(strSourceOutputReaderRecPath, source_readerdom.OuterXml, false, "content,ignorechecktimestamp", source_reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; // 写回目标读者记录 lRet = channel.DoSaveTextRes(strTargetOutputReaderRecPath, target_readerdom.OuterXml, false, "content,ignorechecktimestamp", source_reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
// 初始化所有数据库 public int ClearAllDbs( RmsChannelCollection Channels, out string strError) { strError = ""; string strTempError = ""; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "GetChannel error"; return -1; } long lRet = 0; // 大书目库 for (int i = 0; i < this.ItemDbs.Count; i++) { ItemDbCfg cfg = this.ItemDbs[i]; // 实体库 string strEntityDbName = cfg.DbName; if (String.IsNullOrEmpty(strEntityDbName) == false) { lRet = channel.DoInitialDB(strEntityDbName, out strTempError); if (lRet == -1) { strError += "清除实体库 '" + strEntityDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } // 订购库 string strOrderDbName = cfg.OrderDbName; if (String.IsNullOrEmpty(strOrderDbName) == false) { lRet = channel.DoInitialDB(strOrderDbName, out strTempError); if (lRet == -1) { strError += "清除订购库 '" + strOrderDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } // 期库 string strIssueDbName = cfg.IssueDbName; if (String.IsNullOrEmpty(strIssueDbName) == false) { lRet = channel.DoInitialDB(strIssueDbName, out strTempError); if (lRet == -1) { strError += "清除期库 '" + strIssueDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } // 小书目库 string strBiblioDbName = cfg.BiblioDbName; if (String.IsNullOrEmpty(strBiblioDbName) == false) { lRet = channel.DoInitialDB(strBiblioDbName, out strTempError); if (lRet == -1) { strError += "清除小书目库 '" + strBiblioDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } } // 读者库 for (int i = 0; i < this.ReaderDbs.Count; i++) { string strDbName = this.ReaderDbs[i].DbName; if (String.IsNullOrEmpty(strDbName) == false) { lRet = channel.DoInitialDB(strDbName, out strTempError); if (lRet == -1) { strError += "清除读者库 '" + strDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } } // 预约到书队列库 if (String.IsNullOrEmpty(this.ArrivedDbName) == false) { string strDbName = this.ArrivedDbName; lRet = channel.DoInitialDB(strDbName, out strTempError); if (lRet == -1) { strError += "清除预约到书库 '" + strDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } // 违约金库 if (String.IsNullOrEmpty(this.AmerceDbName) == false) { string strDbName = this.AmerceDbName; lRet = channel.DoInitialDB(strDbName, out strTempError); if (lRet == -1) { strError += "清除违约金库 '" + strDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } // 发票库 if (String.IsNullOrEmpty(this.InvoiceDbName) == false) { string strDbName = this.InvoiceDbName; lRet = channel.DoInitialDB(strDbName, out strTempError); if (lRet == -1) { strError += "清除发票库 '" + strDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } // 消息库 if (String.IsNullOrEmpty(this.MessageDbName) == false) { string strDbName = this.MessageDbName; lRet = channel.DoInitialDB(strDbName, out strTempError); if (lRet == -1) { strError += "清除消息库 '" + strDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } // 实用库 XmlNodeList nodes = this.LibraryCfgDom.DocumentElement.SelectNodes("utilDb/database"); for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strDbName = DomUtil.GetAttr(node, "name"); string strType = DomUtil.GetAttr(node, "type"); if (String.IsNullOrEmpty(strDbName) == false) { lRet = channel.DoInitialDB(strDbName, out strTempError); if (lRet == -1) { strError += "清除类型为 "+strType+" 的实用库 '" + strDbName + "' 内数据时候发生错误:" + strTempError + "; "; } } } if (String.IsNullOrEmpty(strError) == false) return -1; return 0; }
// SetBiblioInfo() API 或CopyBiblioInfo() API 的恢复动作 // 函数内,使用return -1;还是goto ERROR1; 要看错误发生的时候,是否还有价值继续探索SnapShot重试。如果是,就用后者。 /* <root> <operation>setBiblioInfo</operation> <action>...</action> 具体动作 有 new/change/delete/onlydeletebiblio/onlydeletesubrecord 和 onlycopybiblio/onlymovebiblio/copy/move <record recPath='中文图书/3'>...</record> 记录体 动作为new/change/ *move* / *copy* 时具有此元素(即delete时没有此元素) <oldRecord recPath='中文图书/3'>...</oldRecord> 被覆盖、删除或者移动的记录 动作为change/ *delete* / *move* / *copy* 时具备此元素 <deletedEntityRecords> 被删除的实体记录(容器)。只有当<action>为delete时才有这个元素。 <record recPath='中文图书实体/100'>...</record> 这个元素可以重复。注意元素内文本内容目前为空。 ... </deletedEntityRecords> <copyEntityRecords> 被复制的实体记录(容器)。只有当<action>为*copy*时才有这个元素。 <record recPath='中文图书实体/100' targetRecPath='中文图书实体/110'>...</record> 这个元素可以重复。注意元素内文本内容目前为空。recPath属性为源记录路径,targetRecPath为目标记录路径 ... </copyEntityRecords> <moveEntityRecords> 被移动的实体记录(容器)。只有当<action>为*move*时才有这个元素。 <record recPath='中文图书实体/100' targetRecPath='中文图书实体/110'>...</record> 这个元素可以重复。注意元素内文本内容目前为空。recPath属性为源记录路径,targetRecPath为目标记录路径 ... </moveEntityRecords> <copyOrderRecords /> <moveOrderRecords /> <copyIssueRecords /> <moveIssueRecords /> <copyCommentRecords /> <moveCommentRecords /> <operator>test</operator> <operTime>Fri, 08 Dec 2006 10:12:20 GMT</operTime> </root> 逻辑恢复delete操作的时候,检索出全部下属的实体记录删除。 快照恢复的时候,可以根据operlogdom直接删除记录了path的那些实体记录 * */ public int RecoverSetBiblioInfo( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, out string strError) { strError = ""; // 暂时把Robust当作Logic处理 if (level == RecoverLevel.Robust) level = RecoverLevel.Logic; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } bool bReuse = false; // 是否能够不顾RecorverLevel状态而重用部分代码 DO_SNAPSHOT: string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); // 快照恢复 if (level == RecoverLevel.Snapshot || bReuse == true) { byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; if (strAction == "new" || strAction == "change") { XmlNode node = null; string strRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; goto ERROR1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); // 写书目记录 lRet = channel.DoSaveTextRes(strRecPath, strRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入书目记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } } else if (strAction == "onlymovebiblio" || strAction == "onlycopybiblio" || strAction == "move" || strAction == "copy") { XmlNode node = null; string strTargetRecord = DomUtil.GetElementText(domLog.DocumentElement, "record", out node); if (node == null) { strError = "日志记录中缺<record>元素"; goto ERROR1; } string strTargetRecPath = DomUtil.GetAttr(node, "recPath"); string strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } string strOldRecPath = DomUtil.GetAttr(node, "recPath"); string strMergeStyle = DomUtil.GetElementText(domLog.DocumentElement, "mergeStyle"); bool bSourceExist = true; // 观察源记录是否存在 { string strMetaData = ""; string strXml = ""; byte[] temp_timestamp = null; lRet = channel.GetRes(strOldRecPath, out strXml, out strMetaData, out temp_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { bSourceExist = false; } } } if (bSourceExist == true) { string strIdChangeList = ""; // 复制书目记录 lRet = channel.DoCopyRecord(strOldRecPath, strTargetRecPath, strAction == "onlymovebiblio" ? true : false, // bDeleteSourceRecord strMergeStyle, out strIdChangeList, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "DoCopyRecord() error :" + strError; goto ERROR1; } } /* // 写书目记录 lRet = channel.DoSaveTextRes(strRecPath, strRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "复制书目记录 '" + strOldRecPath + "' 到 '" + strTargetRecPath + "' 时发生错误: " + strError; return -1; } * */ if (bSourceExist == false) { if (String.IsNullOrEmpty(strTargetRecord) == true) { if (String.IsNullOrEmpty(strOldRecord) == true) { strError = "源记录 '" + strOldRecPath + "' 不存在,并且<record>元素无文本内容,这时<oldRecord>元素也无文本内容,无法获得要写入的记录内容"; return -1; } strTargetRecord = strOldRecord; } } // 如果有“新记录”内容 if (String.IsNullOrEmpty(strTargetRecord) == false) { // 写书目记录 lRet = channel.DoSaveTextRes(strTargetRecPath, strTargetRecord, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写书目记录 '" + strTargetRecPath + "' 时发生错误: " + strError; return -1; } } // 复制或者移动下级子纪录 if (strAction == "move" || strAction == "copy") { string[] element_names = new string[] { "copyEntityRecords", "moveEntityRecords", "copyOrderRecords", "moveOrderRecords", "copyIssueRecords", "moveIssueRecords", "copyCommentRecords", "moveCommentRecords" }; for (int i = 0; i < element_names.Length; i++) { XmlNode node_subrecords = domLog.DocumentElement.SelectSingleNode( element_names[i]); if (node_subrecords != null) { nRet = CopySubRecords( channel, node_subrecords, strTargetRecPath, out strError); if (nRet == -1) return -1; } } } // 2011/12/12 if (bSourceExist == true && (strAction == "move" || strAction == "onlymovebiblio") ) { int nRedoCount = 0; REDO_DELETE: // 删除源书目记录 lRet = channel.DoDeleteRes(strOldRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { // 记录本来就不存在 } else if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO_DELETE; } } else { strError = "删除书目记录 '" + strOldRecPath + "' 时发生错误: " + strError; return -1; } } } } else if (strAction == "delete" || strAction == "onlydeletebiblio" || strAction == "onlydeletesubrecord") { XmlNode node = null; string strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); if (strAction != "onlydeletesubrecord") { int nRedoCount = 0; REDO: // 删除书目记录 lRet = channel.DoDeleteRes(strRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) goto DO_DELETE_CHILD_ENTITYRECORDS; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO; } } strError = "删除书目记录 '" + strRecPath + "' 时发生错误: " + strError; return -1; } } DO_DELETE_CHILD_ENTITYRECORDS: if (strAction == "delete" || strAction == "onlydeletesubrecord") { XmlNodeList nodes = domLog.DocumentElement.SelectNodes("deletedEntityRecords/record"); for (int i = 0; i < nodes.Count; i++) { string strEntityRecPath = DomUtil.GetAttr(nodes[i], "recPath"); /* if (String.IsNullOrEmpty(strEntityRecPath) == true) continue; * */ int nRedoDeleteCount = 0; REDO_DELETE_ENTITY: // 删除实体记录 lRet = channel.DoDeleteRes(strEntityRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoDeleteCount < 10) { timestamp = output_timestamp; nRedoDeleteCount++; goto REDO_DELETE_ENTITY; } } strError = "删除实体记录 '" + strEntityRecPath + "' 时发生错误: " + strError; return -1; } } nodes = domLog.DocumentElement.SelectNodes("deletedOrderRecords/record"); for (int i = 0; i < nodes.Count; i++) { string strOrderRecPath = DomUtil.GetAttr(nodes[i], "recPath"); if (String.IsNullOrEmpty(strOrderRecPath) == true) continue; int nRedoDeleteCount = 0; REDO_DELETE_ORDER: // 删除订购记录 lRet = channel.DoDeleteRes(strOrderRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoDeleteCount < 10) { timestamp = output_timestamp; nRedoDeleteCount++; goto REDO_DELETE_ORDER; } } strError = "删除订购记录 '" + strOrderRecPath + "' 时发生错误: " + strError; return -1; } } nodes = domLog.DocumentElement.SelectNodes("deletedIssueRecords/record"); for (int i = 0; i < nodes.Count; i++) { string strIssueRecPath = DomUtil.GetAttr(nodes[i], "recPath"); if (String.IsNullOrEmpty(strIssueRecPath) == true) continue; int nRedoDeleteCount = 0; REDO_DELETE_ISSUE: // 删除期记录 lRet = channel.DoDeleteRes(strIssueRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoDeleteCount < 10) { timestamp = output_timestamp; nRedoDeleteCount++; goto REDO_DELETE_ISSUE; } } strError = "删除期记录 '" + strIssueRecPath + "' 时发生错误: " + strError; return -1; } } } // end if } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { // 和数据库中已有记录合并,然后保存 if (strAction == "new" || strAction == "change") { // 和SnapShot方式相同 bReuse = true; goto DO_SNAPSHOT; } else if (strAction == "onlymovebiblio" || strAction == "onlycopybiblio" || strAction == "move" || strAction == "copy") { // 和SnapShot方式相同 bReuse = true; goto DO_SNAPSHOT; } else if (strAction == "delete" || strAction == "onlydeletebiblio" || strAction == "onlydeletesubrecord") { XmlNode node = null; string strOldRecord = DomUtil.GetElementText(domLog.DocumentElement, "oldRecord", out node); if (node == null) { strError = "日志记录中缺<oldRecord>元素"; return -1; } string strRecPath = DomUtil.GetAttr(node, "recPath"); if (strAction != "onlydeletesubrecord") { int nRedoCount = 0; byte[] timestamp = null; byte[] output_timestamp = null; REDO: // 删除书目记录 lRet = channel.DoDeleteRes(strRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) goto DO_DELETE_CHILD_ENTITYRECORDS; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO; } } strError = "删除书目记录 '" + strRecPath + "' 时发生错误: " + strError; goto ERROR1; } } DO_DELETE_CHILD_ENTITYRECORDS: if (strAction == "delete" || strAction == "onlydeletesubrecord") { // 删除属于同一书目记录的全部实体记录 // return: // -1 error // 0 没有找到属于书目记录的任何实体记录,因此也就无从删除 // >0 实际删除的实体记录数 nRet = DeleteBiblioChildEntities(channel, strRecPath, null, out strError); if (nRet == -1) { strError = "删除书目记录 '" + strRecPath + "' 下属的实体记录时出错: " + strError; goto ERROR1; } // return: // -1 error // 0 没有找到属于书目记录的任何实体记录,因此也就无从删除 // >0 实际删除的实体记录数 nRet = this.OrderItemDatabase.DeleteBiblioChildItems( // Channels, channel, strRecPath, null, out strError); if (nRet == -1) { strError = "删除书目记录 '" + strRecPath + "' 下属的订购记录时出错: " + strError; goto ERROR1; } // return: // -1 error // 0 没有找到属于书目记录的任何实体记录,因此也就无从删除 // >0 实际删除的实体记录数 nRet = this.IssueItemDatabase.DeleteBiblioChildItems( // Channels, channel, strRecPath, null, out strError); if (nRet == -1) { strError = "删除书目记录 '" + strRecPath + "' 下属的期记录时出错: " + strError; goto ERROR1; } } } else { strError = "无法识别的<action>内容 '" + strAction + "'"; return -1; } } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
/// <summary> /// 检索实用库 /// </summary> /// <param name="Channels"></param> /// <param name="strServerUrl"></param> /// <param name="strDbName"></param> /// <param name="strFrom"></param> /// <param name="strKey"></param> /// <param name="strValueAttrName"></param> /// <param name="strValue"></param> /// <param name="strError"></param> /// <returns></returns> public static int SearchUtilDb( RmsChannelCollection Channels, string strServerUrl, string strDbName, string strFrom, string strKey, string strValueAttrName, out string strValue, out string strError) { strError = ""; strValue = ""; string strPath = ""; RmsChannel channel = Channels.GetChannel(strServerUrl); if (channel == null) { strError = "get channel error"; return -1; } int nRet = SearchOnePath(channel, strDbName, strFrom, strKey, out strPath, out strError); if (nRet == -1) return -1; if (nRet == 0) return 0; // 取记录 string strStyle = "content,data,timestamp"; string strMetaData; string strOutputPath; string strXml = ""; byte[] baTimeStamp = null; long lRet = channel.GetRes(strPath, strStyle, out strXml, out strMetaData, out baTimeStamp, out strOutputPath, out strError); if (lRet == -1) { strError = "检索 '" + strPath + "' 记录体时出错: " + strError; return -1; } XmlDocument domRecord = new XmlDocument(); try { domRecord.LoadXml(strXml); } catch (Exception ex) { strError = "装载路径为'" + strPath + "'的xml记录时出错: " + ex.Message; return -1; } strValue = DomUtil.GetAttr(domRecord.DocumentElement, strValueAttrName); return 1; }
/* foregift 创建押金记录 API: Foregift() <root> <operation>foregift</operation> 操作类型 <action>...</action> 具体动作 目前有foregift return (注: return操作时,overdue元素里面的price属性,可以使用宏 %return_foregift_price% 表示当前剩余的押金额) <readerBarcode>R0000002</readerBarcode> 读者证条码号 <operator>test</operator> 操作者 <operTime>Fri, 08 Dec 2006 04:17:45 GMT</operTime> 操作时间 <overdues>...</overdues> 押金信息 通常内容为一个字符串,为一个或多个<overdue>元素XML文本片断 <readerRecord recPath='...'>...</readerRecord> 最新读者记录 </root> * * */ public int RecoverForegift( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, out string strError) { strError = ""; // 暂时把Robust当作Logic处理 if (level == RecoverLevel.Robust) level = RecoverLevel.Logic; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } DO_SNAPSHOT: // 快照恢复 if (level == RecoverLevel.Snapshot) { XmlNode node = null; string strReaderXml = DomUtil.GetElementText(domLog.DocumentElement, "readerRecord", out node); if (node == null) { strError = "日志记录中缺<readerRecord>元素"; return -1; } string strReaderRecPath = DomUtil.GetAttr(node, "recPath"); byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; // 写读者记录 lRet = channel.DoSaveTextRes(strReaderRecPath, strReaderXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入读者记录 '" + strReaderRecPath + "' 时发生错误: " + strError; return -1; } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { // string strRecoverComment = ""; string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); string strReaderBarcode = DomUtil.GetElementText(domLog.DocumentElement, "readerBarcode"); /// if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "日志记录中<readerBarcode>元素值为空"; goto ERROR1; } string strOperator = DomUtil.GetElementText(domLog.DocumentElement, "operator"); string strOperTime = DomUtil.GetElementText(domLog.DocumentElement, "operTime"); string strOverdues = DomUtil.GetElementText(domLog.DocumentElement, "overdues"); if (String.IsNullOrEmpty(strOverdues) == true) { strError = "日志记录中<overdues>元素值为空"; goto ERROR1; } // 从overdues字符串中分析出id XmlDocument tempdom = new XmlDocument(); tempdom.LoadXml("<root />"); XmlDocumentFragment fragment = tempdom.CreateDocumentFragment(); fragment.InnerXml = strOverdues; tempdom.DocumentElement.AppendChild(fragment); XmlNode tempnode = tempdom.DocumentElement.SelectSingleNode("overdue"); if (tempnode == null) { strError = "<overdues>元素内容有误,缺乏<overdue>元素"; goto ERROR1; } string strID = DomUtil.GetAttr(tempnode, "id"); if (String.IsNullOrEmpty(strID) == true) { strError = "日志记录中<overdues>内容中<overdue>元素中id属性值为空"; goto ERROR1; } // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.GetReaderRecXml( // Channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; goto ERROR1; } if (nRet == -1) { strError = "读入证条码号为 '" + strReaderBarcode + "' 的读者记录时发生错误: " + strError; goto ERROR1; } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; goto ERROR1; } // string strOverdueString = ""; // 根据Foregift() API要求,修改readerdom nRet = DoForegift(strAction, readerdom, ref strID, strOperator, strOperTime, out strOverdueString, out strError); if (nRet == -1) goto ERROR1; // 写回读者、册记录 byte[] output_timestamp = null; string strOutputPath = ""; // 写回读者记录 lRet = channel.DoSaveTextRes(strOutputReaderRecPath, readerdom.OuterXml, false, "content,ignorechecktimestamp", reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }
/// <summary> /// 写入实用库 /// </summary> /// <param name="Channels"></param> /// <param name="strServerUrl"></param> /// <param name="strDbName"></param> /// <param name="strFrom"></param> /// <param name="strRootElementName"></param> /// <param name="strKeyAttrName"></param> /// <param name="strValueAttrName"></param> /// <param name="strKey"></param> /// <param name="strValue"></param> /// <param name="strError"></param> /// <returns></returns> public static int WriteUtilDb( RmsChannelCollection Channels, string strServerUrl, string strDbName, string strFrom, string strRootElementName, string strKeyAttrName, string strValueAttrName, string strKey, string strValue, out string strError) { strError = ""; string strPath = ""; RmsChannel channel = Channels.GetChannel(strServerUrl); if (channel == null) { strError = "get channel error"; return -1; } int nRet = SearchOnePath(channel, strDbName, strFrom, strKey, out strPath, out strError); if (nRet == -1) return -1; string strXml = ""; if (nRet == 0) { strPath = strDbName + "/?"; strXml = "<" + strRootElementName + " " + strKeyAttrName + "='" + strKey + "' " + strValueAttrName + "='" + strValue + "'/>"; //bNewRecord = true; } else { string strPartXml = "/xpath/<locate>@" + strValueAttrName + "</locate><create>@" + strValueAttrName + "</create>"; strPath += strPartXml; strXml = strValue; //bNewRecord = false; } byte[] baTimestamp = null; byte[] baOutputTimeStamp = null; string strOutputPath = ""; REDO: channel = Channels.GetChannel(strServerUrl); if (channel == null) { strError = "get channel error"; return -1; } long lRet = channel.DoSaveTextRes(strPath, strXml, false, // bInlucdePreamble "ignorechecktimestamp", // style baTimestamp, out baOutputTimeStamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { baTimestamp = baOutputTimeStamp; goto REDO; } return -1; } return 1; }
/* settlement 结算违约金 API: Settlement() <root> <operation>settlement</operation> 操作类型 <action>...</action> 具体动作 有settlement undosettlement delete 3种 <id>1234567-1</id> ID <operator>test</operator> 操作者 <operTime>Fri, 08 Dec 2006 04:17:45 GMT</operTime> 操作时间 <oldAmerceRecord recPath='...'>...</oldAmerceRecord> 旧违约金记录 <amerceRecord recPath='...'>...</amerceRecord> 新违约金记录 delete操作无此元素 </root> * */ public int RecoverSettlement( RmsChannelCollection Channels, RecoverLevel level, XmlDocument domLog, out string strError) { strError = ""; // 暂时把Robust当作Logic处理 if (level == RecoverLevel.Robust) level = RecoverLevel.Logic; long lRet = 0; int nRet = 0; RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } DO_SNAPSHOT: // 快照恢复 if (level == RecoverLevel.Snapshot) { string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); if (strAction == "settlement" || strAction == "undosettlement") { XmlNode node = null; string strAmerceXml = DomUtil.GetElementText(domLog.DocumentElement, "amerceRecord", out node); if (node == null) { strError = "日志记录中缺<amerceRecord>元素"; return -1; } string strAmerceRecPath = DomUtil.GetAttr(node, "recPath"); byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; // 写违约金记录 lRet = channel.DoSaveTextRes(strAmerceRecPath, strAmerceXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "写入违约金记录 '" + strAmerceRecPath + "' 时发生错误: " + strError; return -1; } } else if (strAction == "delete") { XmlNode node = null; string strOldAmerceXml = DomUtil.GetElementText(domLog.DocumentElement, "oldAmerceRecord", out node); if (node == null) { strError = "日志记录中缺<oldAmerceRecord>元素"; return -1; } string strOldAmerceRecPath = DomUtil.GetAttr(node, "recPath"); // 删除违约金记录 int nRedoCount = 0; byte[] timestamp = null; byte[] output_timestamp = null; REDO_DELETE: lRet = channel.DoDeleteRes(strOldAmerceRecPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) return 0; // 记录本来就不存在 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount < 10) { timestamp = output_timestamp; nRedoCount++; goto REDO_DELETE; } } strError = "删除违约金记录 '" + strOldAmerceRecPath + "' 时发生错误: " + strError; return -1; } } else { strError = "未能识别的action值 '" + strAction + "'"; } return 0; } // 逻辑恢复或者混合恢复 if (level == RecoverLevel.Logic || level == RecoverLevel.LogicAndSnapshot) { string strAction = DomUtil.GetElementText(domLog.DocumentElement, "action"); string strID = DomUtil.GetElementText(domLog.DocumentElement, "id"); /// if (String.IsNullOrEmpty(strID) == true) { strError = "日志记录中<id>元素值为空"; goto ERROR1; } string strOperator = DomUtil.GetElementText(domLog.DocumentElement, "operator"); string strOperTime = DomUtil.GetElementText(domLog.DocumentElement, "operTime"); // 通过id获得违约金记录的路径 string strText = ""; string strCount = ""; strCount = "<maxCount>100</maxCount>"; strText = "<item><word>" + StringUtil.GetXmlStringSimple(strID) + "</word>" + strCount + "<match>exact</match><relation>=</relation><dataType>string</dataType>" + "</item>"; string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(this.AmerceDbName + ":" + "ID") // 2007/9/14 + "'>" + strText + "<lang>zh</lang></target>"; lRet = channel.DoSearch(strQueryXml, "amerced", "", // strOuputStyle out strError); if (lRet == -1) { strError = "检索ID为 '" + strID + "' 的违约金记录出错: " + strError; goto ERROR1; } if (lRet == 0) { strError = "没有找到id为 '" + strID + "' 的违约金记录"; goto ERROR1; } List<string> aPath = null; lRet = channel.DoGetSearchResult( "amerced", // strResultSetName 0, 1, "zh", null, // stop out aPath, out strError); if (lRet == -1) goto ERROR1; if (lRet == 0) { strError = "获取结果集未命中"; goto ERROR1; } if (aPath.Count != 1) { strError = "aPath.Count != 1"; goto ERROR1; } string strAmerceRecPath = aPath[0]; // 结算一个交费记录 // parameters: // bCreateOperLog 是否创建日志 // strOperTime 结算的操作时间 // strOperator 结算的操作者 // return: // -2 致命出错,不宜再继续循环调用本函数 // -1 一般出错,可以继续循环调用本函数 // 0 正常 nRet = SettlementOneRecord( "", // 确保可以执行 false, // 不创建日志 channel, strAction, strAmerceRecPath, strOperTime, strOperator, "", // 表示本机触发 out strError); if (nRet == -1 || nRet == -2) goto ERROR1; } return 0; ERROR1: if (level == RecoverLevel.LogicAndSnapshot) { level = RecoverLevel.Snapshot; goto DO_SNAPSHOT; } return -1; }