public DefaultThread(LibraryApplication app, string strName) : base(app, strName) { this.Loop = true; this.PerTime = 5 * 60 * 1000; // 5分钟 }
// 构造函数 public DkywReplication(LibraryApplication app, string strName) : base(app, strName) { this.Loop = true; this.PerTime = 5 * 60 * 1000; // 5分钟 }
// 构造函数 public PatronReplication(LibraryApplication app, string strName) : base(app, strName) { this.Loop = true; // 调试 // this.PerTime = 5 * 60 * 1000; // 5分钟 }
public int Initial( LibraryApplication app, out string strError) { strError = ""; this.App = app; // 2013/5/11 this.m_lock.AcquireWriterLock(m_nLockTimeout); try { LoadCurrentFile(); } finally { this.m_lock.ReleaseWriterLock(); } return 0; }
public OperLogThread(LibraryApplication app, string strName) : base(app, strName) { this.Loop = true; this.PerTime = 5 * 60 * 1000; // 5分钟 if (string.IsNullOrEmpty(this.App.OutgoingQueue) == false) { try { _queue = new MessageQueue(this.App.OutgoingQueue); _queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); } catch (Exception ex) { string strError = "OperLogThread 构造时,创建路径为 '" + this.App.OutgoingQueue + "' 的 MessageQueue 对象失败: " + ex.Message; this.App.WriteErrorLog(strError); } } else this._queue = null; }
// 将种记录数据从XML格式转换为HTML格式 // parameters: // strBiblioXml XML记录,或者 MARC 记录 // strSyntax MARC格式 usmarc/unimarc。如果strBiblioXml 第一字符为 '<' 则本参数可以为空 public int ConvertBiblioXmlToHtml( string strFilterFileName, string strBiblioXml, string strSyntax, string strRecPath, string strStyle, out string strBiblio, out string strError) { strBiblio = ""; strError = ""; int nRet = 0; LibraryApplication app = this; FilterHost host = new FilterHost(); host.RecPath = strRecPath; host.Style = strStyle; host.App = this; string strMarc = ""; if (string.IsNullOrEmpty(strBiblioXml) == false && strBiblioXml[0] == '<') { // 如果必要,转换为MARC格式,调用filter // string strOutMarcSyntax = ""; // 将MARCXML格式的xml记录转换为marc机内格式字符串 // parameters: // bWarning ==true, 警告后继续转换,不严格对待错误; = false, 非常严格对待错误,遇到错误后不继续转换 // strMarcSyntax 指示marc语法,如果=="",则自动识别 // strOutMarcSyntax out参数,返回marc,如果strMarcSyntax == "",返回找到marc语法,否则返回与输入参数strMarcSyntax相同的值 nRet = MarcUtil.Xml2Marc(strBiblioXml, true, "", // this.CurMarcSyntax, out strSyntax, out strMarc, out strError); if (nRet == -1) { goto ERROR1; } } else { strMarc = strBiblioXml; } LoanFilterDocument filter = null; nRet = app.PrepareMarcFilter( // host, strFilterFileName, out filter, out strError); if (nRet == -1) { goto ERROR1; } filter.FilterHost = host; try { nRet = filter.DoRecord(null, strMarc, strSyntax, 0, out strError); if (nRet == -1) { goto ERROR1; } strBiblio = host.ResultString; } catch (Exception ex) { strError = "filter.DoRecord error: " + ExceptionUtil.GetDebugText(ex); return(-1); } finally { // 2012/3/28 filter.FilterHost = null; // 脱钩 // 归还对象 app.Filters.SetFilter(strFilterFileName, filter); } return(0); ERROR1: return(-1); }
public CommentItemDatabase(LibraryApplication app) : base(app) { }
// 将一般库记录数据从XML格式转换为HTML格式 // parameters: // strRecPath 记录路径。用途是为了给宿主对象的RecPath成员赋值 // 2009/10/18 // return: // -2 基类为ReaderConverter public int ConvertRecordXmlToHtml( string strCsFileName, string strRefFileName, string strXml, string strRecPath, out string strResult, out string strError) { strResult = ""; strError = ""; LibraryApplication app = this; // 转换为html格式 Assembly assembly = null; int nRet = app.GetXml2HtmlAssembly( strCsFileName, strRefFileName, app.BinDir, out assembly, out strError); if (nRet == -1) { goto ERROR1; } // 得到Assembly中RecordConverter派生类Type Type entryClassType = ScriptManager.GetDerivedClassType( assembly, "DigitalPlatform.LibraryServer.RecordConverter"); if (entryClassType == null) { // 当没有找到RecordConverter的派生类时, // 继续从代码中找一下有没有ReaderConverter的派生类,如果有,则返回-2,这样函数返回后就为调主多提供了一点信息,便于后面继续处理 entryClassType = ScriptManager.GetDerivedClassType( assembly, "DigitalPlatform.LibraryServer.ReaderConverter"); if (entryClassType == null) { strError = "从DigitalPlatform.LibraryServer.RecordConverter派生的类 type entry not found"; goto ERROR1; } return(-2); } // new一个RecordConverter派生对象 RecordConverter obj = (RecordConverter)entryClassType.InvokeMember(null, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null); // 为RecordConverter派生类设置参数 obj.App = app; obj.RecPath = strRecPath; // 调用关键函数Convert try { strResult = obj.Convert(strXml); } catch (Exception ex) { strError = "脚本执行时抛出异常: " + ExceptionUtil.GetDebugText(ex); goto ERROR1; } return(0); ERROR1: return(-1); }
public IssueItemDatabase(LibraryApplication app) : base(app) { }
public OrderItemDatabase(LibraryApplication app) : base(app) { }
void RenderReservation(LibraryApplication app, SessionInfo sessioninfo, XmlDocument dom) { // 预约请求 PlaceHolder reservation = (PlaceHolder)this.FindControl("reservation"); this.ReservationBarcodes = new List<string>(); XmlNodeList nodes = dom.DocumentElement.SelectNodes("reservations/request"); this.ReservationLineCount = nodes.Count; for (int i = 0; i < nodes.Count; i++) { PlaceHolder line = (PlaceHolder)reservation.FindControl("reservation_line" + Convert.ToString(i)); if (line == null) { Control insertpos = reservation.FindControl("reservation_insertpos"); line = NewReservationLine(insertpos.Parent, i, insertpos); //this.ReservationLineCount++; } line.Visible = true; LiteralControl left = (LiteralControl)line.FindControl("reservation_line" + Convert.ToString(i) + "left"); CheckBox checkbox = (CheckBox)line.FindControl("reservation_line" + Convert.ToString(i) + "checkbox"); LiteralControl right = (LiteralControl)line.FindControl("reservation_line" + Convert.ToString(i) + "right"); XmlNode node = nodes[i]; string strBarcodes = DomUtil.GetAttr(node, "items"); this.ReservationBarcodes.Add(strBarcodes); string strRequestDate = ItemConverter.LocalTime(DomUtil.GetAttr(node, "requestDate")); string strResult = ""; string strClass = " class='roundcontentdark' "; if ((i % 2) == 1) strClass = " class='roundcontentlight' "; strResult += "<tr " + strClass + "><td nowrap>"; // 左 left.Text = strResult; // 右开始 strResult = " "; //strResult += "" + strBarcodes + "</td>"; strResult += "" + MakeBarcodeListHyperLink(strBarcodes, ",") + "</td>"; // 操作者 string strOperator = DomUtil.GetAttr(node, "operator"); // 状态 string strArrivedDate = DomUtil.GetAttr(node, "arrivedDate"); string strState = DomUtil.GetAttr(node, "state"); // 2007/1/18 string strArrivedItemBarcode = DomUtil.GetAttr(node, "arrivedItemBarcode"); if (strState == "arrived") { strArrivedDate = ItemConverter.LocalTime(strArrivedDate); strState = "册 "+strArrivedItemBarcode+" 已于 " + strArrivedDate + " 到书"; } strResult += "<td>" + strState + "</td>"; string strSummary = app.GetBarcodesSummary( sessioninfo, strBarcodes, "html", ""); /* string strSummary = ""; string strPrevBiblioRecPath = ""; string[] barcodes = strBarcodes.Split(new char[] {','}); for (int j = 0; j < barcodes.Length; j++) { string strBarcode = barcodes[j]; if (String.IsNullOrEmpty(strBarcode) == true) continue; // 获得摘要 string strOneSummary = ""; string strBiblioRecPath = ""; Result result = app.GetBiblioSummary(sessioninfo, strBarcode, strPrevBiblioRecPath, // 前一个path out strBiblioRecPath, out strOneSummary); if (result.Value == -1 || result.Value == 0) strOneSummary = result.ErrorInfo; if (strOneSummary == "" && strPrevBiblioRecPath == strBiblioRecPath) strOneSummary = "(同上)"; strSummary += strBarcode + " : " + strOneSummary + "<br/>"; strPrevBiblioRecPath = strBiblioRecPath; } */ strResult += "<td width='50%'>" + strSummary + "</td>"; strResult += "<td nowrap>" + strRequestDate + "</td>"; strResult += "<td nowrap>" + strOperator + "</td>"; strResult += "</tr>"; right.Text = strResult; } // 把多余的行隐藏起来 for (int i = nodes.Count; ; i++) { PlaceHolder line = (PlaceHolder)reservation.FindControl("reservation_line" + Convert.ToString(i)); if (line == null) break; line.Visible = false; } }
// 观察历史字符串的某位的 'y'/'n' 状态 // parameters: // strBodyType 通知消息的接口 (媒体) 类型 // nTimeIndex 2013/9/24 催还的次数下标。0 表示已经超期时的催还,1 等以后的值表示配置字符串中定义的特定次数的提醒通知,也就是尚未超期时候的提醒 public static bool IsNotified( LibraryApplication app, string strBodyType, int nTimeIndex, string strHistory) { Debug.Assert(nTimeIndex >= 0, ""); int nExtendCount = 0; // 扩展接口的个数 if (app.m_externalMessageInterfaces != null) nExtendCount = app.m_externalMessageInterfaces.Count; int nSegmentLength = nExtendCount + 2; // 每个小部分的长度 int index = -1; // 0: dpmail; 1: email; >=2: 其他扩充的消息接口方式 if (strBodyType == "dpmail") { index = 0; } else if (strBodyType == "email") { index = 1; } else { MessageInterface external_interface = app.GetMessageInterface(strBodyType); if (external_interface == null) { // strError = "不能识别的 message type '" + strBodyType + "'"; // return -1; return false; } index = app.m_externalMessageInterfaces.IndexOf(external_interface); if (index == -1) { // strError = "external_interface (type '" + external_interface.Type + "') 没有在 m_externalMessageInterfaces 数组中找到"; // return -1; return false; } index += 2; } // 计算在整体中的偏移 index = (nSegmentLength * nTimeIndex) + index; if (strHistory.Length < index + 1) return false; if (strHistory[index] == 'y') return true; return false; }
void BuildAmerceRecord(XmlDocument domOperLog, out string strBodyXml, out string strReaderBarcode, out string strReaderRefID) { strBodyXml = ""; strReaderBarcode = ""; strReaderRefID = ""; string strError = ""; // string strOperation = DomUtil.GetElementText(domOperLog.DocumentElement, "operation"); string strAction = DomUtil.GetElementText(domOperLog.DocumentElement, "action"); string strLibraryCode = DomUtil.GetElementText(domOperLog.DocumentElement, "libraryCode"); string strReaderRecord = DomUtil.GetElementText(domOperLog.DocumentElement, "readerRecord"); XmlDocument readerdom = new XmlDocument(); readerdom.LoadXml(strReaderRecord); strReaderRefID = DomUtil.GetElementText(readerdom.DocumentElement, "refID"); strReaderBarcode = DomUtil.GetElementText(readerdom.DocumentElement, "barcode"); // 构造内容 XmlDocument bodydom = new XmlDocument(); bodydom.LoadXml("<root />"); if (strAction == "amerce") { DomUtil.SetElementText(bodydom.DocumentElement, "type", "交费"); } else if (strAction == "undo") { DomUtil.SetElementText(bodydom.DocumentElement, "type", "撤销交费"); } else if (strAction == "modifyprice") { // DomUtil.SetElementText(bodydom.DocumentElement, "type", "变更交费金额"); strBodyXml = ""; return; } else if (strAction == "expire") { DomUtil.SetElementText(bodydom.DocumentElement, "type", "以停代金到期"); } else if (strAction == "modifycomment") { // DomUtil.SetElementText(bodydom.DocumentElement, "type", "修改交费注释"); strBodyXml = ""; return; } else { #if NO strError = "无法识别的 strAction '" + strAction + "'"; throw new Exception(strError); #endif strBodyXml = ""; return; } // 复制日志记录中的一级元素 XmlNodeList nodes = domOperLog.DocumentElement.SelectNodes("*"); foreach (XmlNode node in nodes) { if (node.Name == "readerRecord" || node.Name == "oldReaderRecord" || node.Name == "expireOverdues" || node.Name == "amerceItems" || node.Name == "amerceRecord") { continue; } DomUtil.SetElementText(bodydom.DocumentElement, node.Name, node.InnerText); } { XmlElement record = bodydom.CreateElement("patronRecord"); bodydom.DocumentElement.AppendChild(record); record.InnerXml = readerdom.DocumentElement.InnerXml; DomUtil.DeleteElement(record, "borrowHistory"); DomUtil.DeleteElement(record, "password"); DomUtil.DeleteElement(record, "fingerprint"); DomUtil.DeleteElement(record, "face"); DomUtil.SetElementText(record, "libraryCode", strLibraryCode); } // items XmlElement amerce_items = bodydom.DocumentElement.SelectSingleNode("items") as XmlElement; if (amerce_items == null) { amerce_items = bodydom.CreateElement("items"); bodydom.DocumentElement.AppendChild(amerce_items); } XmlNodeList amerce_records = domOperLog.DocumentElement.SelectNodes("amerceRecord"); foreach (XmlElement amerce_record in amerce_records) { string strAmercedXml = amerce_record.InnerText; if (string.IsNullOrEmpty(strAmercedXml)) { continue; } string strOverdueString = ""; string strTemp = ""; int nRet = LibraryApplication.ConvertAmerceRecordToOverdueString(strAmercedXml, out strTemp, out strOverdueString, out strError); if (nRet == -1) { throw new Exception(strError); } XmlDocumentFragment fragment = bodydom.CreateDocumentFragment(); fragment.InnerXml = strOverdueString; amerce_items.AppendChild(fragment); } // expire 情况要把 expireOverdues/overdue 翻译为 items/overdue 元素 if (strAction == "expire") { XmlElement expireOverdues = domOperLog.DocumentElement.SelectSingleNode("expiredOverdues") as XmlElement; if (expireOverdues != null) { amerce_items.InnerXml = expireOverdues.InnerXml; } } else { // 留着 amerceItem 元素做测试对照 } RmsChannel channel = this.RmsChannels.GetChannel(this.App.WsUrl); if (channel == null) { strError = "channel == null"; throw new Exception(strError); } // 为 overdue 元素添加 summary 属性 XmlNodeList overdues = bodydom.DocumentElement.SelectNodes("items/overdue"); foreach (XmlElement overdue in overdues) { string strItemBarcode = overdue.GetAttribute("barcode"); if (string.IsNullOrEmpty(strItemBarcode)) { continue; } // 加入书目摘要 string strSummary = ""; string strBiblioRecPath = ""; LibraryServerResult result = this.App.GetBiblioSummary( null, channel, strItemBarcode, "", // strItemRecPath, null, out strBiblioRecPath, out strSummary); if (result.Value == -1) { // strSummary = result.ErrorInfo; } else { overdue.SetAttribute("summary", strSummary); } } strBodyXml = bodydom.DocumentElement.OuterXml; }
public OperLogRecover(LibraryApplication app, string strName) : base(app, strName) { this.PerTime = 0; }
public BuildMongoOperDatabase(LibraryApplication app, string strName) : base(app, strName) { this.PerTime = 0; }
// 将一条 borrow 或 return 操作日志信息加入 mongodb 日志库 // mongodb 日志库的意义在于提供借阅历史检索功能 public static int AppendOperationBorrowReturn( LibraryApplication app, XmlDocument domOperLog, string strOperation, out string strError) { strError = ""; string strAction = DomUtil.GetElementText(domOperLog.DocumentElement, "action"); ChargingOperItem item = new ChargingOperItem(); item.Operation = strOperation; item.Action = strAction; item.LibraryCode = DomUtil.GetElementText(domOperLog.DocumentElement, "libraryCode"); item.ItemBarcode = DomUtil.GetElementText(domOperLog.DocumentElement, "itemBarcode"); item.PatronBarcode = DomUtil.GetElementText(domOperLog.DocumentElement, "readerBarcode"); { string strBiblioRecPath = DomUtil.GetElementText(domOperLog.DocumentElement, "biblioRecPath"); if (string.IsNullOrEmpty(strBiblioRecPath) == false) item.BiblioRecPath = strBiblioRecPath; } if (strOperation == "borrow") { item.Period = DomUtil.GetElementText(domOperLog.DocumentElement, "borrowPeriod"); item.No = DomUtil.GetElementText(domOperLog.DocumentElement, "no"); } if (strOperation == "return" && strAction == "read") { // no 用作卷册信息 item.No = DomUtil.GetElementText(domOperLog.DocumentElement, "no"); } item.ClientAddress = DomUtil.GetElementText(domOperLog.DocumentElement, "clientAddress"); item.Operator = DomUtil.GetElementText(domOperLog.DocumentElement, "operator"); string strOperTime = DomUtil.GetElementText(domOperLog.DocumentElement, "operTime"); try { item.OperTime = DateTimeUtil.FromRfc1123DateTimeString(strOperTime).ToLocalTime(); } catch (Exception ex) { strError = "operTime 元素内容 '" + strOperTime + "' 格式错误:" + ex.Message; return -1; } app.ChargingOperDatabase.Add(item); return 0; }
// 构造函数 public ZhengyuanReplication(LibraryApplication app, string strName) : base(app, strName) { this.Loop = true; }
// 根据检索参数创建XML检索式 public static int BuildQueryXml( LibraryApplication app, string strDbName, string strWord, string strFrom, string strMatchStyle, int nMaxCount, out string strXml, out string strError) { strError = ""; strXml = ""; if (app == null) { strError = "app == null"; return -1; } if (app.vdbs == null) { strError = "app.vdbs == null"; return -1; } if (String.IsNullOrEmpty(strDbName) == true) { strError = "strDbName参数不能为空。"; return -1; } // // 数据库是不是虚拟库? VirtualDatabase vdb = app.vdbs[strDbName]; // 需要增加一个索引器 if (vdb == null) { strError = "书目库名 '" + strDbName + "' 不存在。"; return -1; } string strOneDbQuery = ""; // 如果是虚拟库 if (vdb.IsVirtual == true) { int nRet = BuildVirtualQuery( app.vdbs.db_dir_results, vdb, strWord, strFrom, strMatchStyle, nMaxCount, out strOneDbQuery, out strError); if (nRet == -1) return -1; } else { // 2007/4/5 改造 加上了 GetXmlStringSimple() strOneDbQuery = "<target list='" + StringUtil.GetXmlStringSimple(strDbName + ":" + strFrom) // 2007/9/14 + "'><item><word>" + StringUtil.GetXmlStringSimple(strWord) + "</word><match>" + strMatchStyle + "</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>zh</lang></target>"; } strXml = strOneDbQuery; return 0; }
// 根据检索参数创建XML检索式 // return: // -1 出错 // 0 不存在所指定的数据库或者检索途径。一个都没有 // 1 成功 public static int BuildQueryXml( LibraryApplication app, string strDbName, string strWord, string strFrom, string strMatchStyle, string strRelation, string strDataType, int nMaxCount, out string strXml, out string strError) { strError = ""; strXml = ""; if (app == null) { strError = "app == null"; return -1; } if (app.vdbs == null) { strError = "app.vdbs == null"; return -1; } if (String.IsNullOrEmpty(strDbName) == true) { strError = "strDbName参数不能为空。"; return -1; } if (String.IsNullOrEmpty(strMatchStyle) == true) strMatchStyle = "middle"; if (String.IsNullOrEmpty(strRelation) == true) strRelation = "="; if (String.IsNullOrEmpty(strDataType) == true) strDataType = "string"; // // 数据库是不是虚拟库? VirtualDatabase vdb = app.vdbs[strDbName]; // 需要增加一个索引器 string strOneDbQuery = ""; // 如果是虚拟库 if (vdb != null && vdb.IsVirtual == true) { int nRet = BuildVirtualQuery( app.vdbs.db_dir_results, vdb, strWord, strFrom, strMatchStyle, nMaxCount, out strOneDbQuery, out strError); if (nRet == -1) return -1; } else { /* // 2007/4/5 改造 加上了 GetXmlStringSimple() strOneDbQuery = "<target list='" + StringUtil.GetXmlStringSimple(strDbName + ":" + strFrom) // 2007/9/14 + "'><item><word>" + StringUtil.GetXmlStringSimple(strWord) + "</word><match>" + strMatchStyle + "</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>zh</lang></target>"; * */ string strTargetList = ""; if (String.IsNullOrEmpty(strDbName) == true || strDbName.ToLower() == "<all>" || strDbName == "<全部>") { List<string> found_dup = new List<string>(); // 用于去重 if (app.vdbs.Count == 0) { strError = "目前library.xml中<virtualDatabases>内尚未配置检索目标"; return 0; } // 所有虚拟库包含的去重后的物理库名 和全部物理名 (整体去重一次) // 要注意检查特定的from名在物理库中是否存在,如果不存在则排除该库名 for (int j = 0; j < app.vdbs.Count; j++) { VirtualDatabase temp_vdb = app.vdbs[j]; // 需要增加一个索引器 // 忽略具有notInAll属性的库 if (temp_vdb.NotInAll == true) continue; List<string> realdbs = new List<string>(); // if (temp_vdb.IsVirtual == true) realdbs = temp_vdb.GetRealDbNames(); for (int k = 0; k < realdbs.Count; k++) { // 数据库名 string strOneDbName = realdbs[k]; if (found_dup.IndexOf(strOneDbName) != -1) continue; strTargetList += StringUtil.GetXmlStringSimple(strOneDbName + ":" + strFrom) + ";"; found_dup.Add(strOneDbName); } } } else if (String.IsNullOrEmpty(strDbName) == true || strDbName.ToLower() == "<all items>" || strDbName == "<全部实体>" || strDbName.ToLower() == "<all comments>" || strDbName == "<全部评注>") { if (app.ItemDbs.Count == 0) { strError = "目前library.xml中<itemdbgroup>内尚未配置数据库"; return -1; } string strDbType = ""; if (strDbName.ToLower() == "<all items>" || strDbName == "<全部实体>") strDbType = "item"; else if (strDbName.ToLower() == "<all comments>" || strDbName == "<全部评注>") strDbType = "comment"; else { Debug.Assert(false, ""); } for (int j = 0; j < app.ItemDbs.Count; j++) { ItemDbCfg cfg = app.ItemDbs[j]; string strOneDbName = ""; if (strDbType == "item") strOneDbName = cfg.DbName; else if (strDbType == "comment") strOneDbName = cfg.CommentDbName; if (String.IsNullOrEmpty(strOneDbName) == true) continue; strTargetList += StringUtil.GetXmlStringSimple(strOneDbName + ":" + strFrom) + ";"; } } else { strTargetList = StringUtil.GetXmlStringSimple(strDbName + ":" + strFrom); } if (String.IsNullOrEmpty(strTargetList) == true) { strError = "不具备任何检索目标"; return 0; } strOneDbQuery = "<target list='" + strTargetList + "'><item><word>" + StringUtil.GetXmlStringSimple(strWord) + "</word><match>" + StringUtil.GetXmlStringSimple(strMatchStyle) + "</match>" + "<relation>" + StringUtil.GetXmlStringSimple(strRelation) + "</relation>" + "<dataType>" + StringUtil.GetXmlStringSimple(strDataType) + "</dataType>" + "<maxCount>" + (-1).ToString() + "</maxCount></item><lang>zh</lang></target>"; } strXml = strOneDbQuery; return 1; }
// 将刚从dt1000升级上来的读者和实体记录进行交叉处理 // parameters: // nStart 从第几个借阅的册事项开始处理 // nCount 共处理几个借阅的册事项 // nProcessedBorrowItems [out]本次处理了多少个借阅册事项 // nTotalBorrowItems [out]当前读者一共包含有多少个借阅册事项 // result.Value // -1 错误。 // 0 成功。 // 1 有警告 public LibraryServerResult CrossRefBorrowInfo( // RmsChannelCollection Channels, RmsChannel channel, string strReaderBarcode, int nStart, int nCount, out int nProcessedBorrowItems, out int nTotalBorrowItems) { string strError = ""; nTotalBorrowItems = 0; nProcessedBorrowItems = 0; int nRet = 0; string strWarning = ""; int nRedoCount = 0; // string strCheckError = ""; LibraryServerResult result = new LibraryServerResult(); // int nErrorCount = 0; REDO_CHANGE_READERREC: // 加读者记录锁 #if DEBUG_LOCK_READER this.WriteErrorLog("CrossRefBorrowInfo 开始为读者加写锁 '" + strReaderBarcode + "'"); #endif this.ReaderLocks.LockForWrite(strReaderBarcode); try // 读者记录锁定范围开始 { // 读入读者记录 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) { result.Value = -1; result.ErrorInfo = "读者证条码号 '" + strReaderBarcode + "' 不存在"; result.ErrorCode = ErrorCode.ReaderBarcodeNotFound; return(result); } 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; } bool bReaderRecChanged = false; // 修改读者记录中overdues/overdue中的价格单位,并加入id // return: // -1 error // 0 not changed // 1 changed nRet = ModifyReaderRecord( ref readerdom, out strWarning, out strError); if (nRet == -1) { goto ERROR1; } if (nRet == 1) { bReaderRecChanged = true; } // TODO: strWarning内容如何处理? XmlNodeList nodesBorrow = readerdom.DocumentElement.SelectNodes("borrows/borrow"); nTotalBorrowItems = nodesBorrow.Count; if (nTotalBorrowItems == 0) { result.Value = 0; result.ErrorInfo = "读者记录中没有借还信息。"; return(result); } if (nStart >= nTotalBorrowItems) { strError = "nStart参数值" + nStart.ToString() + "大于当前读者记录中的借阅册个数" + nTotalBorrowItems.ToString(); goto ERROR1; } nProcessedBorrowItems = 0; for (int i = nStart; i < nTotalBorrowItems; i++) { if (nCount != -1 && nProcessedBorrowItems >= nCount) { break; } // 一个API最多做10条 if (nProcessedBorrowItems >= 10) { break; } XmlNode nodeBorrow = nodesBorrow[i]; string strItemBarcode = DomUtil.GetAttr(nodeBorrow, "barcode"); nProcessedBorrowItems++; if (String.IsNullOrEmpty(strItemBarcode) == true) { strWarning += "读者记录中<borrow>元素barcode属性值不能为空; "; continue; } string strBorrowDate = DomUtil.GetAttr(nodeBorrow, "borrowDate"); string strBorrowPeriod = DomUtil.GetAttr(nodeBorrow, "borrowPeriod"); if (String.IsNullOrEmpty(strBorrowDate) == true) { strWarning += "读者记录中<borrow>元素borrowDate属性不能为空; "; continue; } if (String.IsNullOrEmpty(strBorrowPeriod) == true) { strWarning += "读者记录中<borrow>元素borrowPeriod属性不能为空; "; continue; } // 把实体记录借阅信息详细化 // return: // 0 册条码号没有找到对应的册记录 // 1 成功 nRet = ModifyEntityRecord( // Channels, channel, null, // strEntityRecPath strItemBarcode, strReaderBarcode, strBorrowDate, strBorrowPeriod, out strError); if (nRet == -1) { strWarning += "ModifyEntityRecord() [strItemBarcode='" + strItemBarcode + "' strReaderBarcode='" + strReaderBarcode + "'] error : " + strError + "; "; continue; } // 2008/10/7 if (nRet == 0) { strWarning += "册条码号 '" + strItemBarcode + "' 对应的记录不存在; "; continue; } } if (bReaderRecChanged == true) { byte[] output_timestamp = null; string strOutputPath = ""; #if NO RmsChannel channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; goto ERROR1; } #endif // 写回读者记录 long lRet = channel.DoSaveTextRes(strOutputReaderRecPath, readerdom.OuterXml, false, "content", // ,ignorechecktimestamp reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { nRedoCount++; if (nRedoCount > 10) { strError = "写回读者记录的时候,遇到时间戳冲突,并因此重试10次,仍失败..."; goto ERROR1; } goto REDO_CHANGE_READERREC; } goto ERROR1; } // 及时更新时间戳 reader_timestamp = output_timestamp; } } finally { this.ReaderLocks.UnlockForWrite(strReaderBarcode); #if DEBUG_LOCK_READER this.WriteErrorLog("CrossRefBorrowInfo 结束为读者加写锁 '" + strReaderBarcode + "'"); #endif } if (String.IsNullOrEmpty(strWarning) == false) { result.Value = 1; result.ErrorInfo = strWarning; } else { result.Value = 0; } return(result); ERROR1: result.Value = -1; result.ErrorInfo = strError; result.ErrorCode = ErrorCode.SystemError; return(result); }
// 修改册记录中的借期,并去掉 overflow 元素 int ModifyItemRecord( SessionInfo sessioninfo, ItemModifyInfo info, out string strError) { strError = ""; int nRet = 0; string strFrom = "册条码号"; // 获得册记录 var result = GetItemRecord(sessioninfo, info.ItemBarcode, null, // strOwnerInstitution, ref strFrom, info.ConfirmItemRecPath, // ref strLibraryCode, out List <string> aPath, out string strItemXml, out string strOutputItemRecPath, out byte[] item_timestamp); if (aPath.Count > 1) { strError = $"册条码号为 {info.ItemBarcode} 的册记录有 {aPath.Count} 条,无法进行借阅操作"; return(-1); } if (result.Value == -1) { strError = result.ErrorInfo; return(-1); } XmlDocument itemdom = null; nRet = LibraryApplication.LoadToDom(strItemXml, out itemdom, out strError); if (nRet == -1) { strError = "装载册记录进入XML DOM时发生错误: " + strError; return(-1); } // 修改 DomUtil.SetElementText(itemdom.DocumentElement, "borrowPeriod", info.BorrowPeriod); if (string.IsNullOrEmpty(info.DenyPeriod) == false) { DomUtil.SetElementText(itemdom.DocumentElement, "denyPeriod", info.DenyPeriod); } else { DomUtil.DeleteElement(itemdom.DocumentElement, "denyPeriod"); } DomUtil.SetElementText(itemdom.DocumentElement, "returningDate", info.ReturningDate); DomUtil.DeleteElement(itemdom.DocumentElement, "overflow"); RmsChannel channel = sessioninfo.Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return(-1); } // 写回册记录 long lRet = channel.DoSaveTextRes(strOutputItemRecPath, itemdom.OuterXml, false, "content", item_timestamp, out byte[] output_timestamp, out string strOutputPath, out strError); if (lRet == -1) { return(-1); } return(0); }
void RenderOverdue( LibraryApplication app, SessionInfo sessioninfo, XmlDocument dom) { PlaceHolder overdueinfo = (PlaceHolder)this.FindControl("overdueinfo"); XmlNodeList nodes = dom.DocumentElement.SelectNodes("overdues/overdue"); for (int i = 0; i < nodes.Count; i++) { PlaceHolder line = (PlaceHolder)overdueinfo.FindControl("overdueinfo_line" + Convert.ToString(i)); if (line == null) { Control insertpos = overdueinfo.FindControl("overdueinfo_insertpos"); line = NewOverdueLine(insertpos.Parent, i, insertpos); } line.Visible = true; LiteralControl left = (LiteralControl)line.FindControl("overdueinfo_line" + Convert.ToString(i) + "left"); XmlNode node = nodes[i]; string strBarcode = DomUtil.GetAttr(node, "barcode"); string strItemRecPath = DomUtil.GetAttr(node, "recPath"); string strReason = DomUtil.GetAttr(node, "reason"); string strBorrowDate = DomUtil.GetAttr(node, "borrowDate"); string strPeriod = DomUtil.GetAttr(node, "borrowPeriod"); string strReturnDate = DomUtil.GetAttr(node, "returnDate"); string strClass = " class='roundcontentdark' "; if ((i % 2) == 1) strClass = " class='roundcontentlight' "; string strResult = "<tr " + strClass + " nowrap><td nowrap>"; strResult += " "; strResult += "<a href='book.aspx?barcode=" + strBarcode + "&itemrecpath=" + strItemRecPath + "'>" + strBarcode + "</a></td>"; // 获得摘要 string strSummary = ""; string strBiblioRecPath = ""; LibraryServerResult result = app.GetBiblioSummary( sessioninfo, strBarcode, strItemRecPath, null, out strBiblioRecPath, out strSummary); if (result.Value == -1 || result.Value == 0) strSummary = result.ErrorInfo; strResult += "<td width='50%'>" + strSummary + "</td>"; strResult += "<td >" + strReason + "</td>"; strResult += "<td nowrap>" + ItemConverter.LocalTime(strBorrowDate) + "</td>"; strResult += "<td nowrap>" + strPeriod + "</td>"; strResult += "<td>" + strReturnDate + "</td>"; strResult += "</tr>"; left.Text = strResult; } // 把多余的行隐藏起来 for (int i = nodes.Count; ; i++) { PlaceHolder line = (PlaceHolder)overdueinfo.FindControl("overdueinfo_line" + Convert.ToString(i)); if (line == null) break; line.Visible = false; } }
// parameters: // now 当前时间。本地时间格式。这是用来判断是否超期的依据 static bool IsOverdue(XmlElement borrow, DateTime now, out List <string> warnings) { warnings = new List <string>(); StringBuilder debugInfo = null; // 看看是否已经超期。已经超期的不处理 string returningDate = borrow.GetAttribute("returningDate"); // 2020/9/14 // 较旧的 dp2library 版本中没有 returningDate 属性,这种情况意味着所借图书的借阅时间很早很早了,可以简单当作已经超期来处理 // 注:也可以考虑这里尝试用 borrowDate 加上 borrowPeriod 来计算出应还时间,只是比较麻烦一点 if (string.IsNullOrEmpty(returningDate) == true) { return(true); } debugInfo?.AppendLine($"returningDate='{returningDate}'"); DateTime returningTime = DateTimeUtil.FromRfc1123DateTimeString(returningDate).ToLocalTime(); string period = borrow.GetAttribute("borrowPeriod"); debugInfo?.AppendLine($"borrowPeriod='{period}'"); int nRet = LibraryApplication.ParsePeriodUnit(period, out long lPeriodValue, out string strPeriodUnit, out string strError); if (nRet == -1) { debugInfo?.AppendLine($"ParsePeriodUnit('{period}') 出错:{strError}。只好把时间单位当作 day 来处理"); strPeriodUnit = "day"; // continue; } // DateTime now = DateTime.Now; // 正规化时间 nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref now, out strError); if (nRet == -1) { warnings.Add($"正规化时间出错(1)。strPeriodUnit={strPeriodUnit}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); return(false); } nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref returningTime, out strError); if (nRet == -1) { warnings.Add($"正规化时间出错(2)。strPeriodUnit={strPeriodUnit}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); return(false); } if (returningTime < now) { debugInfo?.AppendLine($"已经超期,跳过处理 (returningTime={returningTime.ToString()}, now={now.ToString()})"); return(true); } return(false); }
// 一次操作循环 public override void Worker() { // 系统挂起的时候,不运行本线程 // 2007/12/18 //if (this.App.HangupReason == HangupReason.LogRecover) // return; if (this.App.ContainsHangup("LogRecover") == true) { return; } // 2012/2/4 if (this.App.PauseBatchTask == true) { return; } bool bFirst = true; string strError = ""; int nRet = 0; BatchTaskStartInfo startinfo = this.StartInfo; if (startinfo == null) { startinfo = new BatchTaskStartInfo(); // 按照缺省值来 } // 通用启动参数 bool bLoop = true; nRet = ParseMessageMonitorParam(startinfo.Param, out bLoop, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); return; } this.Loop = bLoop; string strID = ""; nRet = ParseMessageMonitorStart(startinfo.Start, out strID, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); this.Loop = false; return; } // bool bPerDayStart = false; // 是否为每日一次启动模式 string strMonitorName = "messageMonitor"; { string strLastTime = ""; nRet = ReadLastTime( strMonitorName, out strLastTime, out strError); if (nRet == -1) { string strErrorText = "从文件中获取 " + strMonitorName + " 每日启动时间时发生错误: " + strError; this.AppendResultText(strErrorText + "\r\n"); this.App.WriteErrorLog(strErrorText); return; } string strStartTimeDef = ""; // bRet 是否到了每日启动时间 bool bRet = false; string strOldLastTime = strLastTime; // return: // -2 strLastTime 格式错误 // -1 一般错误 // 0 没有找到startTime配置参数 // 1 找到了startTime配置参数 nRet = IsNowAfterPerDayStart( strMonitorName, ref strLastTime, out bRet, out strStartTimeDef, out strError); if (nRet == -1 || nRet == -2) { string strErrorText = "获取 " + strMonitorName + " 每日启动时间时发生错误: " + strError; this.AppendResultText(strErrorText + "\r\n"); this.App.WriteErrorLog(strErrorText); if (nRet == -2) { // 删除断点文件,避免下次继续报错 WriteLastTime(strMonitorName, ""); } return; } // 如果nRet == 0,表示没有配置相关参数,则兼容原来的习惯,每次都作 if (nRet == 0) { } else if (nRet == 1) { if (bRet == false) { if (this.ManualStart == true) { this.AppendResultText("已试探启动任务 '" + this.Name + "',但因没有到每日启动时间 " + strStartTimeDef + " 而未能启动。(上次任务处理结束时间为 " + DateTimeUtil.LocalTime(strLastTime) + ")\r\n"); } // 2014/3/31 if (string.IsNullOrEmpty(strOldLastTime) == true && string.IsNullOrEmpty(strLastTime) == false) { this.AppendResultText("史上首次启动此任务。已把当前时间当作上次任务处理结束时间 " + DateTimeUtil.LocalTime(strLastTime) + " 写入了断点记忆文件\r\n"); WriteLastTime(strMonitorName, strLastTime); } return; // 还没有到每日时间 } bPerDayStart = true; } this.App.WriteErrorLog((bPerDayStart == true ? "(定时)" : "(不定时)") + strMonitorName + " 启动。"); } AppendResultText("开始新一轮循环"); RmsChannel channel = this.RmsChannels.GetChannel(this.App.WsUrl); string strMessageDbName = this.App.MessageDbName; if (String.IsNullOrEmpty(strMessageDbName) == true) { AppendResultText("尚未配置消息库名(<message dbname='...' />)"); this.Loop = false; return; } if (String.IsNullOrEmpty(this.App.MessageReserveTimeSpan) == true) { AppendResultText("尚未配置消息保留期限(<message reserveTimeSpan='...' />"); this.Loop = false; return; } // 解析期限值 string strPeriodUnit = ""; long lPeriodValue = 0; nRet = LibraryApplication.ParsePeriodUnit( this.App.MessageReserveTimeSpan, out lPeriodValue, out strPeriodUnit, out strError); if (nRet == -1) { strError = "消息保留期限 值 '" + this.App.MessageReserveTimeSpan + "' 格式错误: " + strError; AppendResultText(strError); this.Loop = false; return; } AppendResultText("开始处理消息库 " + strMessageDbName + " 的循环"); // string strID = "1"; int nRecCount = 0; for (; ; nRecCount++) { // 系统挂起的时候,不运行本线程 // 2008/2/4 if (this.App.ContainsHangup("LogRecover") == true) { break; } // 2012/2/4 if (this.App.PauseBatchTask == true) { break; } if (this.Stopped == true) { break; } string strStyle = ""; strStyle = "data,content,timestamp,outputpath"; if (bFirst == true) { strStyle += ""; } else { strStyle += ",next"; } string strPath = strMessageDbName + "/" + strID; string strXmlBody = ""; string strMetaData = ""; string strOutputPath = ""; byte[] baOutputTimeStamp = null; // SetProgressText((nRecCount + 1).ToString() + " " + strPath); // 获得资源 // return: // -1 出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。 // 0 成功 long lRet = channel.GetRes(strPath, strStyle, out strXmlBody, out strMetaData, out baOutputTimeStamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { if (bFirst == true) { // 第一条没有找到, 但是要强制循环进行 bFirst = false; goto CONTINUE; } else { if (bFirst == true) { strError = "数据库 " + strMessageDbName + " 记录 " + strID + " 不存在。处理结束。"; } else { strError = "数据库 " + strMessageDbName + " 记录 " + strID + " 是最末一条记录。处理结束。"; } break; } } else if (channel.ErrorCode == ChannelErrorCode.EmptyRecord) { bFirst = false; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); goto CONTINUE; } goto ERROR1; } bFirst = false; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); try { // 处理 nRet = DoOneRecord( lPeriodValue, strPeriodUnit, strOutputPath, strXmlBody, baOutputTimeStamp, out strError); } catch (Exception ex) { strError = "DoOneRecord exception: " + ExceptionUtil.GetDebugText(ex); this.AppendResultText(strError + "\r\n"); this.SetProgressText(strError); nRet = -1; } if (nRet == -1) { AppendResultText("DoOneRecord() error : " + strError + "。\r\n"); } CONTINUE: continue; } // end of for // 正常结束,复位断点 this.App.RemoveBatchTaskBreakPointFile(this.Name); this.StartInfo.Start = ""; AppendResultText("针对消息库 " + strMessageDbName + " 的循环结束。共处理 " + nRecCount.ToString() + " 条记录。\r\n"); { Debug.Assert(this.App != null, ""); // 写入文件,记忆已经做过的当日时间 string strLastTime = DateTimeUtil.Rfc1123DateTimeStringEx(this.App.Clock.UtcNow.ToLocalTime()); // 2007/12/17 changed // DateTime.UtcNow // 2012/5/27 WriteLastTime(strMonitorName, strLastTime); string strErrorText = (bPerDayStart == true ? "(定时)" : "(不定时)") + strMonitorName + "结束。共处理记录 " + nRecCount.ToString() + " 个。"; this.App.WriteErrorLog(strErrorText); } return; ERROR1: // 记忆断点 this.StartInfo.Start = MemoBreakPoint( strID //strRecordID, ); this.Loop = true; // 便于稍后继续重新循环? startinfo.Param = MakeMessageMonitorParam( bLoop); AppendResultText("MessageMonitor thread error : " + strError + "\r\n"); this.App.WriteErrorLog("MessageMonitor thread error : " + strError + "\r\n"); return; }
// 针对读者记录中的 borrow 元素中 overflow (尚未超期)的,重新计算是否超额。如果不超额的,修改为正常的借期 // parameters: // now 当前时间。本地时间格式。这是用来判断是否超期的依据 // return.Value: // -1 出错 // 0 成功 // 1 有警告信息,在 strError 中返回 internal AdjustOverflowResult AdjustOverflow( XmlDocument readerdom, DateTime now, StringBuilder debugInfo) { List <ItemModifyInfo> modifies = new List <ItemModifyInfo>(); int nRet = BuildBorrowItemInfo(readerdom, now, out List <BorrowItemInfo> items, out string strError); if (nRet == -1) { return new AdjustOverflowResult { Value = -1, ErrorInfo = strError, Modifies = modifies } } ; // 没有任何在借事项 if (items.Count == 0) { return new AdjustOverflowResult { Value = 0, Modifies = modifies } } ; int overflow_count = BorrowItemInfo.CountOverflow(items); // 没有超额事项可供调整 if (overflow_count == 0) { return new AdjustOverflowResult { Value = 0, Modifies = modifies } } ; // 获得总的最大可借数 // return: // -1 出错 // 其他 最大可借册数 int totalMax = GetTotalMax( readerdom, out strError); if (totalMax == -1) { return new AdjustOverflowResult { Value = -1, ErrorInfo = strError, Modifies = modifies } } ; List <string> warnings = new List <string>(); var groups = BorrowItemInfo.GroupByBookType(items); // 对每种图书类型,尝试修正到本类型的最大许可外借数 foreach (var group in groups) { string bookType = group[0].BookType; // 获得特定图书类型的最大可借数 // return: // -1 出错 // 其他 此类型图书的最大可借册数 int typeMax = GetTypeMax( readerdom, bookType, out strError); if (typeMax == -1) { warnings.Add(strError); continue; // 放弃这一类型的处理,继续处理其他类型 } while (true) { // 统计数组中,正常借阅(非超额)的数量 int count = BorrowItemInfo.CountNormal(group); if (count < typeMax) { // 尝试从中改掉一个 overflow // return: // true 成功改掉一个 // false 没能改掉。(原因可能是因为没有可以改动状态的 overflow 元素了) var item = BorrowItemInfo.DecOverflow(group); if (item == null) { break; } // 检查总册数是否超额。如果超额,刚才的改动需要 undo int totalCount = BorrowItemInfo.CountNormal(items); if (totalCount > totalMax) { item.ModifyAction = null; // Undo break; } } else { break; } } } // 开始修改 borrow 元素 foreach (var item in items) { if (item.ModifyAction != "removeOverflow") { continue; } string strOldBorrowInfo = item.Element.OuterXml; // 获得一册书的借阅参数 nRet = GetBorrowParam( readerdom, item.BookType, item.BorrowDate, out string borrowPeriod, out string denyPeriod, out string returningDate, out strError); if (nRet == -1) { warnings.Add(strError); continue; } item.Element.SetAttribute("borrowPeriod", borrowPeriod); if (string.IsNullOrEmpty(denyPeriod) == false) { item.Element.SetAttribute("denyPeriod", denyPeriod); } else { item.Element.RemoveAttribute("denyPeriod"); } item.Element.SetAttribute("returningDate", returningDate); // 删除 overflow 属性 item.Element.RemoveAttribute("overflow"); modifies.Add(new ItemModifyInfo { LibraryCode = DomUtil.GetElementText(readerdom.DocumentElement, "libraryCode"), PatronBarcode = DomUtil.GetElementText(readerdom.DocumentElement, "barcode"), BorrowID = item.Element.GetAttribute("borrowID"), ItemBarcode = item.Barcode, BorrowDate = item.Element.GetAttribute("borrowDate"), BorrowPeriod = borrowPeriod, DenyPeriod = denyPeriod, ReturningDate = returningDate, OldBorrowInfo = strOldBorrowInfo, }); } /* * // 修改涉及到的册记录 * if (modifies.Count > 0 && sessioninfo != null) * { * foreach (var info in modifies) * { * nRet = ModifyItemRecord( * sessioninfo, * info, * out strError); * if (nRet == -1) * { * warnings.Add($"修改册记录 {info.ItemBarcode} 过程中出错: {strError}"); * debugInfo?.Append($"{warnings[warnings.Count - 1]}"); * } * } * } */ if (warnings.Count > 0) { strError = StringUtil.MakePathList(warnings, "; "); return(new AdjustOverflowResult { Value = 1, ErrorInfo = strError, Modifies = modifies }); } return(new AdjustOverflowResult { Value = 0, Modifies = modifies }); } #if NO // 针对读者记录中的 borrow 元素中 overflow (尚未超期)的,重新计算是否超额。如果不超额的,修改为正常的借期 // return: // -1 出错 // 0 成功 // 1 有警告信息,在 strError 中返回 int AdjustOverflow( SessionInfo sessioninfo, XmlDocument readerdom, StringBuilder debugInfo, out string strError) { strError = ""; int nRet = 0; debugInfo.AppendLine($"用于调整的读者记录: {DomUtil.GetIndentXml(readerdom)}"); List <string> warnings = new List <string>(); List <ItemModifyInfo> items = new List <ItemModifyInfo>(); string libraryCode = DomUtil.GetElementText(readerdom.DocumentElement, "libraryCode"); string readerType = DomUtil.GetElementText(readerdom.DocumentElement, "readerType"); // List<XmlElement> overflows = new List<XmlElement>(); debugInfo?.AppendLine($"libraryCode='{libraryCode}'"); debugInfo?.AppendLine($"readerType='{readerType}'"); var nodes = readerdom.DocumentElement.SelectNodes("borrows/borrow"); foreach (XmlElement borrow in nodes) { debugInfo?.AppendLine($"=== 对 borrow 元素进行处理: {borrow.OuterXml}"); if (borrow.HasAttribute("overflow") == false) { debugInfo?.AppendLine("没有 overflow 属性,跳过处理"); continue; } string no = borrow.GetAttribute("no"); if (string.IsNullOrEmpty(no) == false) { if (Int32.TryParse(no, out int value) == true) { if (value > 0) { debugInfo?.AppendLine("续借的情况跳过处理"); continue; // 续借的情况不考虑 } } else { warnings.Add($"续借次数 '{no}' 格式错误"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } } string itemBarcode = borrow.GetAttribute("barcode"); if (string.IsNullOrEmpty(itemBarcode)) { itemBarcode = "@refid:" + borrow.GetAttribute("refID"); } debugInfo?.AppendLine($"条码号='{itemBarcode}'"); try { // 获得借阅开始时间 string borrowDate = borrow.GetAttribute("borrowDate"); debugInfo?.AppendLine($"borrowDate='{borrowDate}'"); DateTime borrowTime = DateTimeUtil.FromRfc1123DateTimeString(borrowDate).ToLocalTime(); // 看看是否已经超期。已经超期的不处理 { string returningDate = borrow.GetAttribute("returningDate"); debugInfo?.AppendLine($"returningDate='{returningDate}'"); DateTime returningTime = DateTimeUtil.FromRfc1123DateTimeString(returningDate).ToLocalTime(); string period = borrow.GetAttribute("borrowPeriod"); debugInfo?.AppendLine($"borrowPeriod='{period}'"); nRet = LibraryApplication.ParsePeriodUnit(period, out long lPeriodValue, out string strPeriodUnit, out strError); if (nRet == -1) { debugInfo?.AppendLine($"ParsePeriodUnit('{period}') 出错:{strError}。只好把时间单位当作 day 来处理"); strPeriodUnit = "day"; // continue; } DateTime now = DateTime.Now; // 正规化时间 nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref now, out strError); if (nRet == -1) { warnings.Add($"正规化时间出错(1)。strPeriodUnit={strPeriodUnit}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref returningTime, out strError); if (nRet == -1) { warnings.Add($"正规化时间出错(2)。strPeriodUnit={strPeriodUnit}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (returningTime < now) { debugInfo?.AppendLine($"已经超期,跳过处理 (returningTime={returningTime.ToString()}, now={now.ToString()})"); continue; } } string bookType = borrow.GetAttribute("type"); debugInfo?.AppendLine($"bookType='{bookType}'"); // 假设要首次借阅这一册,是否会超额? { // 从读者信息中,找出该读者以前已经借阅过的同类图书的册数 int nThisTypeCount = readerdom.DocumentElement.SelectNodes("borrows/borrow[@type='" + bookType + "']").Count; nRet = this.GetLoanParam( //null, libraryCode, readerType, bookType, "可借册数", out string strParamValue, out MatchResult _, out strError); if (nRet == -1) { warnings.Add($"获得 馆代码 '{ libraryCode }' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 可借册数 参数时发生错误: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (nRet < 4) { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 可借册数 参数无法获得: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (Int32.TryParse(strParamValue, out int thisTypeMax) == false) { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 可借册数 参数 '{strParamValue}' 格式错误"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } // 依然超额了。不修改 if (nThisTypeCount > thisTypeMax) { debugInfo?.AppendLine($"特定类型的图书超额了,跳过处理。nThisTypeCount={nThisTypeCount}, thisTypeMax={thisTypeMax}, bookType={bookType}, readerType={readerType}"); continue; } // 看 可借总册数 nRet = this.GetLoanParam( //null, libraryCode, readerType, "", "可借总册数", out strParamValue, out MatchResult _, out strError); if (nRet == -1) { warnings.Add($"获得 馆代码 '{ libraryCode }' 中 读者类型 '{ readerType }' 的 可借总册数 参数时发生错误: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (nRet < 3) { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 的 可借总册数 参数无法获得: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (Int32.TryParse(strParamValue, out int max) == false) { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 的 可借总册数 参数 '{strParamValue}' 格式错误"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } // 从读者信息中,找出该读者已经借阅过的册数 int count = readerdom.DocumentElement.SelectNodes("borrows/borrow").Count; // 依然超额了。不修改 if (count > max) { debugInfo?.AppendLine($"全部图书超额了,跳过处理。count={count}, max={max}, readerType={readerType}"); continue; } } // return: // reader和book类型均匹配 算4分 // 只有reader类型匹配,算3分 // 只有book类型匹配,算2分 // reader和book类型都不匹配,算1分 nRet = this.GetLoanParam( libraryCode, readerType, bookType, "借期", out string strBorrowPeriodList, out MatchResult matchresult, out strError); if (nRet == -1) { warnings.Add($"获得 馆代码 '{ libraryCode }' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 借期 参数时发生错误: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (nRet < 4) // nRet == 0 { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 借期 参数无法获得: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } string[] aPeriod = strBorrowPeriodList.Split(new char[] { ',' }); if (aPeriod.Length == 0) { warnings.Add($"'{strBorrowPeriodList}' Split error"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } string borrowPeriod = aPeriod[0]; if (string.IsNullOrEmpty(borrowPeriod)) { warnings.Add($"期限字符串 '{strBorrowPeriodList}' 中第一部分 '{borrowPeriod}' 为空"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } nRet = ParseBorrowPeriod(borrowPeriod, out string strThisBorrowPeriod, out string strThisDenyPeriod, out strError); if (nRet == -1) { warnings.Add($"ParseBorrowPeroid() '{borrowPeriod}' error"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } // 计算应还书时间 nRet = ComputeReturningDay( borrowTime, strThisBorrowPeriod, out DateTime this_return_time, out strError); if (nRet == -1) { warnings.Add($"ComputeReturningDay() error. borrowTime='{borrowTime}', strThisBorrowPeriod='{strThisBorrowPeriod}'"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } borrow.SetAttribute("borrowPeriod", strThisBorrowPeriod); // 2016/6/7 if (string.IsNullOrEmpty(strThisDenyPeriod) == false) { borrow.SetAttribute("denyPeriod", strThisDenyPeriod); } else { borrow.RemoveAttribute("denyPeriod"); } string strReturningDate = DateTimeUtil.Rfc1123DateTimeStringEx(this_return_time.ToLocalTime()); borrow.SetAttribute("returningDate", strReturningDate); // 删除 overflow 属性 borrow.RemoveAttribute("overflow"); items.Add(new ItemModifyInfo { ItemBarcode = itemBarcode, BorrowPeriod = strThisBorrowPeriod, DenyPeriod = strThisDenyPeriod, ReturningDate = strReturningDate }); } catch (Exception ex) { warnings.Add($"册记录 {itemBarcode} 处理过程出现异常: {ex.Message}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); } } // 修改涉及到的册记录 if (items.Count > 0) { foreach (var info in items) { nRet = ModifyItemRecord( sessioninfo, info, out strError); if (nRet == -1) { warnings.Add($"修改册记录 {info.ItemBarcode} 过程中出错: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); } } } if (warnings.Count > 0) { strError = StringUtil.MakePathList(warnings, "; "); return(1); } return(0); }
// 合并设置一种 body type 的全部通知字符 // 把 strChars 中的 'y' 设置到 strHistory 中对应达到位。'n' 不设置 public static int SetNotifiedChars(LibraryApplication app, string strBodyType, string strChars, ref string strHistory, out string strError) { strError = ""; int nExtendCount = 0; // 扩展接口的个数 if (app.m_externalMessageInterfaces != null) nExtendCount = app.m_externalMessageInterfaces.Count; int nSegmentLength = nExtendCount + 3; // 原来是 2 // 每个小部分的长度 int index = -1; // 0: dpmail; 1: email; >=2: 其他扩充的消息接口方式 if (strBodyType == "dpmail") { index = 0; } else if (strBodyType == "email") { index = 1; } else if (strBodyType == "mq") { index = 2; } else { MessageInterface external_interface = app.GetMessageInterface(strBodyType); if (external_interface == null) { strError = "不能识别的 message type '" + strBodyType + "'"; return -1; } index = app.m_externalMessageInterfaces.IndexOf(external_interface); if (index == -1) { strError = "external_interface (type '" + external_interface.Type + "') 没有在 m_externalMessageInterfaces 数组中找到"; return -1; } index += 3; // 原来是 2 } for (int i = 0; i < strChars.Length; i++) { char ch = strChars[i]; if (ch == 'n') continue; int nLength = (i + 1) * nSegmentLength; if (strHistory.Length < nLength) strHistory = strHistory.PadRight(nLength, 'n'); int nOffs = i * nSegmentLength + index; strHistory = strHistory.Remove(nOffs, 1); strHistory = strHistory.Insert(nOffs, "y"); } return 0; }
// 将两个订购XML片断合并 // 当旧的和新的都是全管辖范围内,就允许新的全部替换旧的;否则只允许替换<distribute>元素内容 // parameters: // strLibraryCodeList 当前用户管辖的分馆代码列表 // strMergedXml [out]范围订购<root>元素的InnerXml // return: // -1 出错 // 0 正常 // 1 发生了超越范围的修改 // 2 有部分修改需求没有兑现 public int MergeOrderNode(XmlNode exist_node, XmlNode new_node, string strLibraryCodeList, out string strMergedXml, out string strError) { strError = ""; strMergedXml = ""; int nRet = 0; Debug.Assert(SessionInfo.IsGlobalUser(strLibraryCodeList) == false, "全局用户不应调用函数 MergeOrderNode()"); string strExistDistribute = DomUtil.GetElementText(exist_node, "distribute"); string strNewDistribute = DomUtil.GetElementText(new_node, "distribute"); bool bExistControlled = true; bool bNewControlled = true; if (string.IsNullOrEmpty(strExistDistribute) == false) { // 观察一个馆藏分配字符串,看看是否在当前用户管辖范围内 // return: // -1 出错 // 0 超过管辖范围。strError中有解释 // 1 在管辖范围内 nRet = DistributeInControlled(strExistDistribute, strLibraryCodeList, out strError); if (nRet == -1) { return(-1); } if (nRet == 0) { bExistControlled = false; } } if (string.IsNullOrEmpty(strNewDistribute) == false) { // 观察一个馆藏分配字符串,看看是否在当前用户管辖范围内 // return: // -1 出错 // 0 超过管辖范围。strError中有解释 // 1 在管辖范围内 nRet = DistributeInControlled(strNewDistribute, strLibraryCodeList, out strError); if (nRet == -1) { return(-1); } if (nRet == 0) { bNewControlled = false; } } if (bExistControlled == true && bNewControlled == true) { // 当旧的和新的都是全管辖范围内,就允许新的全部替换旧的 strMergedXml = new_node.InnerXml; return(0); } string strExistCopy = DomUtil.GetElementText(exist_node, "copy"); string strExistPrice = DomUtil.GetElementText(exist_node, "price"); string strChangedCopy = DomUtil.GetElementText(new_node, "copy"); string strChangedPrice = DomUtil.GetElementText(new_node, "price"); // 比较两个复本字符串 { string strExistOldValue = ""; string strExistNewValue = ""; IssueItemDatabase.ParseOldNewValue(strExistCopy, out strExistOldValue, out strExistNewValue); string strChangedOldValue = ""; string strChangedNewValue = ""; IssueItemDatabase.ParseOldNewValue(strChangedCopy, out strChangedOldValue, out strChangedNewValue); if (strExistOldValue != strChangedOldValue) { strError = "订购套数(方括号左边的部分)不允许修改。(原来='" + strExistCopy + "',新的='" + strChangedCopy + "')"; return(1); } // 检查验收套数的改变,是否正好和distribute字符串内的改变吻合 } // 比较两个价格字符串 { string strExistOldValue = ""; string strExistNewValue = ""; IssueItemDatabase.ParseOldNewValue(strExistPrice, out strExistOldValue, out strExistNewValue); string strChangedOldValue = ""; string strChangedNewValue = ""; IssueItemDatabase.ParseOldNewValue(strChangedPrice, out strChangedOldValue, out strChangedNewValue); if (strExistOldValue != strChangedOldValue) { strError = "订购价(方括号左边的部分)不允许修改。(原来='" + strExistPrice + "',新的='" + strChangedPrice + "')"; return(1); } if (strExistNewValue != strChangedNewValue) { strError = "验收价(方括中的部分)不允许修改。(原来='" + strExistPrice + "',新的='" + strChangedPrice + "')"; return(1); } } LocationCollection new_locations = new LocationCollection(); nRet = new_locations.Build(strNewDistribute, out strError); if (nRet == -1) { strError = "馆藏分配字符串 '" + strNewDistribute + "' 格式不正确"; return(-1); } LocationCollection exist_locations = new LocationCollection(); nRet = exist_locations.Build(strExistDistribute, out strError); if (nRet == -1) { strError = "馆藏分配字符串 '" + strExistDistribute + "' 格式不正确"; return(-1); } if (exist_locations.Count != new_locations.Count) { strError = "馆藏分配事项个数发生了改变(原来=" + exist_locations.Count.ToString() + ",新的=" + new_locations.Count.ToString() + ")"; return(1); } bool bDistributeChanged = false; for (int i = 0; i < exist_locations.Count; i++) { Location exist_location = exist_locations[i]; Location new_location = new_locations[i]; if (exist_location.Name != new_location.Name) { // 进一步检查是否馆代码部分改变了 string strCode1 = ""; string strPureName = ""; string strCode2 = ""; // 解析 LibraryApplication.ParseCalendarName(exist_location.Name, out strCode1, out strPureName); LibraryApplication.ParseCalendarName(new_location.Name, out strCode2, out strPureName); // 只要馆代码部分不改变即可 if (strCode1 != strCode2) { strError = "第 " + (i + 1).ToString() + " 个馆藏分配事项的名字(的馆代码部分)发生改变 (原来='" + exist_location.Name + "',新的='" + new_location.Name + "')"; return(1); } bDistributeChanged = true; } if (exist_location.RefID != new_location.RefID) { string strLibraryCode = ""; string strPureName = ""; // 解析 LibraryApplication.ParseCalendarName(exist_location.Name, out strLibraryCode, out strPureName); if (StringUtil.IsInList(strLibraryCode, strLibraryCodeList) == false) { strError = "馆代码 '" + strLibraryCode + "' 不在范围 '" + strLibraryCodeList + "' 内,不允许进行收登操作。"; return(1); } bDistributeChanged = true; } } // 将旧的XML片断装入,只修改里面的三个元素值。这样可以保证三个元素以外的原记录内容不被修改 XmlDocument dom = new XmlDocument(); try { dom.LoadXml(exist_node.OuterXml); } catch (Exception ex) { strError = "exist_node.OuterXml装入XMLDOM失败: " + ex.Message; return(-1); } DomUtil.SetElementText(dom.DocumentElement, "copy", strChangedCopy); DomUtil.SetElementText(dom.DocumentElement, "price", strChangedPrice); DomUtil.SetElementText(dom.DocumentElement, "distribute", strNewDistribute); strMergedXml = dom.DocumentElement.InnerXml; List <string> skips = new List <string>(); List <string> differents = null; skips.Add("distribute"); skips.Add("operations"); // parameters: // skips 要跳过的、不参与比较的元素名 // return: // 0 没有差异 // 1 有差异。differents数组里面返回了有差异的元素名 nRet = IsItemInfoChanged(new_node, dom.DocumentElement, skips, out differents); if (nRet == 1) { strError = "对下列元素的修改没有兑现: " + StringUtil.MakePathList(differents); return(2); } if (nRet == 0 && bDistributeChanged == false) { // 没有任何修改发生 } return(0); }
// 将一条 borrow 或 return 操作日志信息加入 mongodb 日志库 // mongodb 日志库的意义在于提供借阅历史检索功能 public static int AppendOperationBorrowReturn( LibraryApplication app, XmlDocument domOperLog, string strOperation, out string strError) { strError = ""; string strAction = DomUtil.GetElementText(domOperLog.DocumentElement, "action"); ChargingOperItem item = new ChargingOperItem(); item.Operation = strOperation; item.Action = strAction; item.LibraryCode = DomUtil.GetElementText(domOperLog.DocumentElement, "libraryCode"); item.ItemBarcode = DomUtil.GetElementText(domOperLog.DocumentElement, "itemBarcode"); item.PatronBarcode = DomUtil.GetElementText(domOperLog.DocumentElement, "readerBarcode"); { string strBiblioRecPath = DomUtil.GetElementText(domOperLog.DocumentElement, "biblioRecPath"); if (string.IsNullOrEmpty(strBiblioRecPath) == false) { item.BiblioRecPath = strBiblioRecPath; } } if (strOperation == "borrow") { item.Period = DomUtil.GetElementText(domOperLog.DocumentElement, "borrowPeriod"); item.No = DomUtil.GetElementText(domOperLog.DocumentElement, "no"); } // 2017/5/22 string strVolume = DomUtil.GetElementText(domOperLog.DocumentElement, "volume"); if (string.IsNullOrEmpty(strVolume) == false) { item.Volume = strVolume; } #if NO if (strOperation == "return" && strAction == "read") { // no 用作卷册信息 ??? item.No = DomUtil.GetElementText(domOperLog.DocumentElement, "no"); } #endif item.ClientAddress = DomUtil.GetElementText(domOperLog.DocumentElement, "clientAddress"); item.Operator = DomUtil.GetElementText(domOperLog.DocumentElement, "operator"); string strOperTime = DomUtil.GetElementText(domOperLog.DocumentElement, "operTime"); try { item.OperTime = DateTimeUtil.FromRfc1123DateTimeString(strOperTime).ToLocalTime(); } catch (Exception ex) { strError = "operTime 元素内容 '" + strOperTime + "' 格式错误:" + ex.Message; return(-1); } app.ChargingOperDatabase.Add(item); return(0); }
// return: // -1 出错 // 0 没有找到指定的参数 // 1 找到指定的参数 public int GetSystemParameter( SessionInfo sessioninfo, string strCategory, string strName, out string strValue, out string strError) { strError = ""; strValue = ""; this.LockForRead(); try { int nRet = 1; // 实用功能 if (strCategory == "utility") { if (strName == "getClientIP") { strValue = sessioninfo.ClientIP; goto END1; } // 用于日志记载的前端地址,包括 IP 和 Via 两个部分 if (strName == "getClientAddress") { strValue = sessioninfo.ClientAddress; goto END1; } } if (strCategory == "listUploadFileNames") { try { string strDirectory = Path.Combine(this.DataDir, "upload/" + strName); strDirectory = strDirectory.Replace("\\", "/"); if (strDirectory[strDirectory.Length - 1] != '/') { strDirectory += "/"; } // 文件名之间的分隔符为 ||,文件名中,和最后修改时间用 | 间隔 List <string> filenames = new List <string>(); DirectoryInfo di = new DirectoryInfo(strDirectory); // 列出所有目录名 DirectoryInfo[] subs = di.GetDirectories(); for (int i = 0; i < subs.Length; i++) { DirectoryInfo sub = subs[i]; filenames.Add(MakeFileName(sub)); // filenames.AddRange(GetFilenames(sub.FullName, true, true)); } // 列出所有文件名 FileInfo[] fis = di.GetFiles(); foreach (FileInfo fi in fis) { filenames.Add(MakeFileName(fi)); } StringBuilder text = new StringBuilder(); string strHead = strDirectory; foreach (string strFilename in filenames) { if (text.Length > 0) { text.Append("||"); } text.Append(strFilename); // 只取出相对部分 // text.Append(strFilename.Substring(strHead.Length)); } strValue = text.ToString(); goto END1; } catch (DirectoryNotFoundException /*ex*/) { strError = "目录 '" + strName + "' 不存在"; goto ERROR1; } } if (strCategory == "cfgs") { // 2015/4/30 if (strName == "getDataDir") { strValue = this.DataDir; goto END1; } if (strName == "listFileNames") { List <string> filenames = new List <string>(); DirectoryInfo di = new DirectoryInfo(this.DataDir + "/cfgs"); DirectoryInfo[] subs = di.GetDirectories(); for (int i = 0; i < subs.Length; i++) { DirectoryInfo sub = subs[i]; filenames.AddRange(GetFilenames(sub.FullName, false, true)); } string strHead = this.DataDir + "/cfgs/"; foreach (string strFilename in filenames) { if (string.IsNullOrEmpty(strValue) == false) { strValue += ","; } // 只取出相对部分 strValue += strFilename.Substring(strHead.Length); } goto END1; } if (strName == "listFileNamesEx") { // 文件名之间的分隔符为 ||,文件名中,和最后修改时间用 | 间隔 List <string> filenames = new List <string>(); DirectoryInfo di = new DirectoryInfo(Path.Combine(this.DataDir, "cfgs")); DirectoryInfo[] subs = di.GetDirectories(); for (int i = 0; i < subs.Length; i++) { DirectoryInfo sub = subs[i]; filenames.AddRange(GetFilenames(sub.FullName, true, true)); } StringBuilder text = new StringBuilder(); string strHead = Path.Combine(this.DataDir, "cfgs/"); foreach (string strFilename in filenames) { if (text.Length > 0) { text.Append("||"); } // 只取出相对部分 text.Append(strFilename.Substring(strHead.Length)); } strValue = text.ToString(); goto END1; } #if NO // 取得文件内容 if (StringUtil.HasHead(strName, "getfile:") == true) { string strFileName = strName.Substring("getfile:".Length); string strFilePath = this.DataDir + "/cfgs/" + strFileName; Encoding encoding = null; // return: // -1 出错 // 0 文件不存在 // 1 文件存在 // 2 读入的内容不是全部 nRet = FileUtil.ReadTextFileContent(strFilePath, 1024 * 1024, // 1M out strValue, out encoding, out strError); if (nRet == -1) { goto ERROR1; } if (nRet == 0) { strError = "文件 '" + strFileName + "' 不存在"; goto ERROR1; } if (nRet == 2) { strError = "文件 '" + strFileName + "' 尺寸太大"; goto ERROR1; } nRet = 1; } #endif } // 获得内核配置文件的时间戳? if (strCategory == "cfgs/get_res_timestamps") { string[] filenames = strName.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); // RemoveEmptyEntries 2013/12/12 // TODO: RmsChannel channel = sessioninfo.Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; goto ERROR1; } StringBuilder text = new StringBuilder(); foreach (string filename in filenames) { string strXml = ""; string strMetaData = ""; byte[] timestamp = null; string strOutputPath = ""; long lRet = channel.GetRes(filename, "timestamp", out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { continue; } goto ERROR1; } if (text.Length > 0) { text.Append(","); } text.Append(filename + "|" + ByteArray.GetHexTimeStampString(timestamp)); } strValue = text.ToString(); goto END1; } if (strCategory == "center") { if (strName == "def") { XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("center"); if (root == null) { strValue = ""; nRet = 0; } else { // 将密码变成明文 strValue = root.OuterXml; if (string.IsNullOrEmpty(strValue) == false) { XmlDocument temp = new XmlDocument(); temp.LoadXml(strValue); XmlNodeList nodes = temp.DocumentElement.SelectNodes("//server"); foreach (XmlNode node in nodes) { string strPassword = DomUtil.GetAttr(node, "password"); strPassword = LibraryApplication.DecryptPassword(strPassword); DomUtil.SetAttr(node, "password", strPassword); } strValue = temp.DocumentElement.OuterXml; } } goto END1; } strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } if (strCategory == "system") { // 2019/1/11 // RFID 相关定义 if (strName == "rfid") { XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("rfid"); if (root == null) { strValue = ""; nRet = 0; } else { strValue = root.OuterXml; } goto END1; } // 2018/7/17 // 获得 dp2library 失效期 if (strName == "expire") { strValue = _expire.ToLongDateString(); goto END1; } // 2018/6/19 // 获得系统挂起状态 if (strName == "hangup") { strValue = StringUtil.MakePathList(this.HangupList); goto END1; } // 2016/6/25 // MSMQ 队列名 if (strName == "outgoingQueue") { strValue = this.OutgoingQueue; goto END1; } // 2016/6/25 // dp2library 版本号 if (strName == "version") { strValue = LibraryApplication.Version; goto END1; } // 2016/4/6 // 获得系统的临时文件目录 if (strName == "systemTempDir") { string strTempFileName = Path.GetTempFileName(); File.Delete(strTempFileName); strValue = Path.GetDirectoryName(strTempFileName); goto END1; } if (strName == "libraryCodes") { List <string> librarycodes = new List <string>(); XmlNodeList nodes = this.LibraryCfgDom.DocumentElement.SelectNodes("readerdbgroup/database"); foreach (XmlNode node in nodes) { string strLibraryCode = DomUtil.GetAttr(node, "libraryCode"); if (string.IsNullOrEmpty(strLibraryCode) == true) { continue; } librarycodes.Add(strLibraryCode); } nodes = this.LibraryCfgDom.DocumentElement.SelectNodes("rightsTable/library"); foreach (XmlNode node in nodes) { string strLibraryCode = DomUtil.GetAttr(node, "code"); if (string.IsNullOrEmpty(strLibraryCode) == true) { continue; } librarycodes.Add(strLibraryCode); } StringUtil.RemoveDupNoSort(ref librarycodes); strValue = StringUtil.MakePathList(librarycodes); goto END1; } if (strName == "arrived") { XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("arrived"); if (root == null) { strValue = ""; nRet = 0; } else { strValue = root.OuterXml; } goto END1; } // 2009/10/23 // 获得<itemdbgroup>元素下级XML if (strName == "biblioDbGroup") { XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("itemdbgroup"); if (root == null) { strValue = ""; nRet = 0; // 注: 返回值为0,字符串为空,错误码不是NotFound,表示想关节点找到了,但值为空 } else { XmlDocument dom = new XmlDocument(); try { dom.LoadXml(root.OuterXml); } catch (Exception ex) { strError = "<itemdbgroup>元素XML片段装入DOM时出错: " + ex.Message; goto ERROR1; } strError = EnsureKdbs(false); if (strError != null) { goto ERROR1; } // 将name属性名修改为itemDbName属性 // TODO: 将来library.xml格式修改后,这部分可以免去了 XmlNodeList nodes = dom.DocumentElement.SelectNodes("database"); for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strItemDbName = DomUtil.GetAttr(node, "name"); DomUtil.SetAttr(node, "name", null); DomUtil.SetAttr(node, "itemDbName", strItemDbName); // 2012/7/2 // 加入各个数据库的多语种名字 // 实体库 AppendCaptions(node, "itemDbName"); // 订购库 AppendCaptions(node, "orderDbName"); // 期库 AppendCaptions(node, "issueDbName"); // 评注库 AppendCaptions(node, "commentDbName"); // 书目库 AppendCaptions(node, "biblioDbName"); } strValue = dom.DocumentElement.InnerXml; } goto END1; } // 2012/9/12 // 获得<readerdbgroup>元素下级XML if (strName == "readerDbGroup") { XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("readerdbgroup"); if (root == null) { strValue = ""; nRet = 0; // 注: 返回值为0,字符串为空,错误码不是NotFound,表示相关节点找到了,但值为空 goto END1; } if (sessioninfo.GlobalUser == true) { strValue = root.InnerXml; } else { // 过滤掉当前用户不能管辖的读者库名 XmlDocument dom = new XmlDocument(); try { dom.LoadXml(root.OuterXml); } catch (Exception ex) { strError = "<readerdbgroup>元素XML片段装入DOM时出错: " + ex.Message; goto ERROR1; } XmlNodeList nodes = dom.DocumentElement.SelectNodes("database"); for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; string strLibraryCode = DomUtil.GetAttr(node, "libraryCode"); if (StringUtil.IsInList(strLibraryCode, sessioninfo.LibraryCodeList) == false) { node.ParentNode.RemoveChild(node); } } strValue = dom.DocumentElement.InnerXml; } goto END1; } strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // OPAC检索 if (strCategory == "opac") { // TODO: 和def重复了,需要合并 // 获得<virtualDatabases>元素下级XML if (strName == "databases") { XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("virtualDatabases"); if (root == null) { strValue = ""; nRet = 0; } else { strValue = root.InnerXml; } goto END1; } // 获得<browseformats>元素下级XML if (strName == "browseformats") { XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("browseformats"); if (root == null) { strValue = ""; nRet = 0; } else { strValue = root.InnerXml; } goto END1; } // 2011/2/15 if (strName == "serverDirectory") { /* * XmlNode node = this.LibraryCfgDom.SelectSingleNode("//opacServer"); * if (node == null) * { * strValue = ""; * nRet = 0; * } * else * strValue = DomUtil.GetAttr(node, "url"); */ strValue = this.OpacServerUrl; goto END1; } strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } if (strCategory == "circulation") { // 2016/1/1 if (strName == "chargingOperDatabase") { if (this.ChargingOperDatabase.Enabled == true) { strValue = "enabled"; } else { strValue = ""; } nRet = 1; goto END1; } // <clientFineInterface>元素内容 // strValue中是OuterXml定义。 if (strName == "clientFineInterface") { XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("clientFineInterface"); if (root == null) { nRet = 0; goto END1; } strValue = root.OuterXml; nRet = 1; goto END1; } // <valueTables>元素内容 // strValue中是下级片断定义,没有<valueTables>元素作为根。 if (strName == "valueTables") { // 按照馆代码列表,返回<valueTables>内的适当片断 nRet = this.GetValueTablesXml( sessioninfo.LibraryCodeList, out strValue, out strError); if (nRet == -1) { goto ERROR1; } nRet = 1; goto END1; } // <rightsTable>元素内容 // strValue中是下级片断定义,没有<rightsTable>元素作为根。 if (strName == "rightsTable") { #if NO XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("rightsTable"); // 0.02前为rightstable if (root == null) { nRet = 0; goto END1; } strValue = root.InnerXml; nRet = 1; goto END1; #endif // 按照馆代码列表,返回<rightsTable>内的适当片断 nRet = this.GetRightsTableXml( sessioninfo.LibraryCodeList, out strValue, out strError); if (nRet == -1) { goto ERROR1; } nRet = 1; goto END1; } // (当前<rightsTable>)权限表的HTML形态 if (strName == "rightsTableHtml") { nRet = this.GetRightTableHtml( "", sessioninfo.LibraryCodeList, out strValue, out strError); if (nRet == -1) { goto ERROR1; } nRet = 1; goto END1; } /* * // 2008/10/10 * // <readertypes>元素内容 * // strValue中是下级片断定义,没有<readertypes>元素作为根。 * if (strName == "readerTypes") * { * XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("rightsTable/readerTypes"); // 0.02前为readertypes * if (root == null) * { * nRet = 0; * goto END1; * } * * strValue = root.InnerXml; * nRet = 1; * goto END1; * } * * // 2008/10/10 * // <booktypes>元素内容 * // strValue中是下级片断定义,没有<booktypes>元素作为根。 * if (strName == "bookTypes") * { * XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("rightsTable/bookTypes"); // 0.02前为booktypes * if (root == null) * { * nRet = 0; * goto END1; * } * * strValue = root.InnerXml; * nRet = 1; * goto END1; * }*/ // 2008/10/10 // <locationtypes>元素内容 // strValue中是下级片断定义,没有<locationTypes>元素作为根。 if (strName == "locationTypes") { #if NO XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("locationTypes"); // 0.02前为locationtypes if (root == null) { nRet = 0; goto END1; } strValue = root.InnerXml; nRet = 1; goto END1; #endif // 按照馆代码列表,返回<locationTypes>内的适当片断 nRet = this.GetLocationTypesXml( sessioninfo.LibraryCodeList, out strValue, out strError); if (nRet == -1) { goto ERROR1; } nRet = 1; goto END1; } // 2008/10/12 // <zhongcihao>元素内容 // strValue中是下级片断定义,没有<zhongcihao>元素作为根。 if (strName == "zhongcihao") { // 分馆用户也能看到全部<zhongcihao>定义 XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("zhongcihao"); if (root == null) { nRet = 0; goto END1; } strValue = root.InnerXml; nRet = 1; goto END1; } // 2009/2/18 // <callNumber>元素内容 // strValue中是下级片断定义,没有<callNumber>元素作为根。 if (strName == "callNumber") { // 分馆用户可以看到全部定义 XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("callNumber"); if (root == null) { nRet = 0; goto END1; } strValue = root.InnerXml; nRet = 1; goto END1; } // 2009/3/9 // <dup>元素内容 // strValue中是下级片断定义,没有<dup>元素作为根。 if (strName == "dup") { // 分馆用户也能看到全部<dup>定义 XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("dup"); if (root == null) { nRet = 0; goto END1; } strValue = root.InnerXml; nRet = 1; goto END1; } // 2008/10/13 2019/5/31 // <script> 或 <barcodeValidation> 元素内容 // strValue中是下级片断定义,没有<script>元素作为根。 if (strName == "script" || strName == "barcodeValidation") { // 分馆用户也能看到全部<script>定义 XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode(strName); if (root == null) { nRet = 0; goto END1; } strValue = root.InnerXml; nRet = 1; goto END1; } strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 根据前端在strName参数中提供的rightstable xml字符串,立即创建rightsTableHtml字符串 if (strCategory == "instance_rightstable_html") { nRet = this.GetRightTableHtml( strName, sessioninfo.LibraryCodeList, out strValue, out strError); if (nRet == -1) { goto ERROR1; } nRet = 1; goto END1; } // 获得内核数据库原始定义 if (strCategory == "database_def") { // strName参数不能为空。本功能只能得到一个数据库的定义,如果要得到全部数据库的定义,请使用ManageDatabase API的getinfo子功能 nRet = this.vdbs.GetDatabaseDef( strName, out strValue, out strError); if (nRet == -1) { goto ERROR1; } goto END1; } // 实用库 if (strCategory == "utilDb") { switch (strName) { case "dbnames": { XmlNodeList nodes = this.LibraryCfgDom.DocumentElement.SelectNodes("//utilDb/database"); for (int i = 0; i < nodes.Count; i++) { string strDbName = DomUtil.GetAttr(nodes[i], "name"); if (i != 0) { strValue += ","; } strValue += strDbName; } } break; case "types": { XmlNodeList nodes = this.LibraryCfgDom.DocumentElement.SelectNodes("//utilDb/database"); for (int i = 0; i < nodes.Count; i++) { string strType = DomUtil.GetAttr(nodes[i], "type"); if (i != 0) { strValue += ","; } strValue += strType; } } break; default: /* * nRet = 0; * break; * */ strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 2009/10/23 goto END1; } if (strCategory == "amerce") { switch (strName) { case "dbname": strValue = this.AmerceDbName; break; case "overduestyle": strValue = this.OverdueStyle; break; default: /* * nRet = 0; * break; * */ strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 2009/10/23 goto END1; } // 2015/6/13 if (strCategory == "arrived") { switch (strName) { case "dbname": strValue = this.ArrivedDbName; break; default: strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } goto END1; } if (strCategory == "biblio") { switch (strName) { case "dbnames": { for (int i = 0; i < this.ItemDbs.Count; i++) { string strDbName = this.ItemDbs[i].BiblioDbName; // 即便数据库名为空,逗号也不能省略。主要是为了准确对位 if (i != 0) { strValue += ","; } strValue += strDbName; } } break; case "syntaxs": { for (int i = 0; i < this.ItemDbs.Count; i++) { string strSyntax = this.ItemDbs[i].BiblioDbSyntax; // 即便strSyntax为空,逗号也不能省略。主要是为了准确对位 if (i != 0) { strValue += ","; } strValue += strSyntax; } } break; default: /* * nRet = 0; * break; * */ strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 2009/10/23 goto END1; } if (strCategory == "virtual") { switch (strName) { // 2011/1/21 case "def": { /* * // TODO: 把这个初始化放在正规的初始化中? * nRet = this.InitialVdbs(sessioninfo.Channels, * out strError); * if (nRet == -1) * { * strError = "InitialVdbs error : " + strError; * goto ERROR1; * } * */ XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode( "virtualDatabases"); if (root == null) { strError = "尚未配置<virtualDatabases>元素"; goto ERROR1; } strValue = root.OuterXml; } break; case "dbnames": { /* * // TODO: 把这个初始化放在正规的初始化中? * nRet = this.InitialVdbs(sessioninfo.Channels, * out strError); * if (nRet == -1) * { * strError = "InitialVdbs error : " + strError; * goto ERROR1; * } * */ if (this.vdbs != null) { for (int i = 0; i < this.vdbs.Count; i++) { VirtualDatabase vdb = this.vdbs[i]; if (vdb.IsVirtual == false) { continue; } if (String.IsNullOrEmpty(strValue) == false) { strValue += ","; } strValue += vdb.GetName("zh"); } } } break; default: strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 2009/10/23 goto END1; } if (strCategory == "item") { switch (strName) { case "dbnames": { for (int i = 0; i < this.ItemDbs.Count; i++) { string strDbName = this.ItemDbs[i].DbName; // 即便strDbName为空,逗号也不能省略。主要是为了准确对位 if (i != 0) { strValue += ","; } strValue += strDbName; } } break; default: strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 2009/10/23 goto END1; } // 2007/10/19 if (strCategory == "issue") { switch (strName) { case "dbnames": { for (int i = 0; i < this.ItemDbs.Count; i++) { string strDbName = this.ItemDbs[i].IssueDbName; // 即便strDbName为空,逗号也不能省略。主要是为了准确对位 if (i != 0) { strValue += ","; } strValue += strDbName; } } break; default: strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 2009/10/23 goto END1; } // 2007/11/30 if (strCategory == "order") { switch (strName) { case "dbnames": { for (int i = 0; i < this.ItemDbs.Count; i++) { string strDbName = this.ItemDbs[i].OrderDbName; // 即便strDbName为空,逗号也不能省略。主要是为了准确对位 if (i != 0) { strValue += ","; } strValue += strDbName; } } break; default: strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 2009/10/23 goto END1; } if (strCategory == "reader") { switch (strName) { case "dbnames": { #if NO for (int i = 0; i < this.ReaderDbs.Count; i++) { string strDbName = this.ReaderDbs[i].DbName; if (String.IsNullOrEmpty(strDbName) == true) { continue; } // 2012/9/7 if (string.IsNullOrEmpty(sessioninfo.LibraryCode) == false) { string strLibraryCode = this.ReaderDbs[i].LibraryCode; // 匹配图书馆代码 // parameters: // strSingle 单个图书馆代码。空的总是不能匹配 // strList 图书馆代码列表,例如"第一个,第二个",或者"*"。空表示都匹配 // return: // false 没有匹配上 // true 匹配上 if (LibraryApplication.MatchLibraryCode(strLibraryCode, sessioninfo.LibraryCode) == false) { continue; } } if (String.IsNullOrEmpty(strValue) == false) { strValue += ","; } strValue += strDbName; } #endif List <string> dbnames = this.GetCurrentReaderDbNameList(sessioninfo.LibraryCodeList); strValue = StringUtil.MakePathList(dbnames); } break; default: strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 2009/10/23 goto END1; } if (strCategory == "library") { switch (strName) { case "name": { XmlNode node = this.LibraryCfgDom.SelectSingleNode("//libraryName"); if (node == null) { strValue = ""; } else { strValue = node.InnerText; } } break; default: strError = "category '" + strCategory + "' 中未知的 name '" + strName + "'"; goto NOTFOUND; } // 2009/10/23 goto END1; } NOTFOUND: if (String.IsNullOrEmpty(strError) == true) { strError = "未知的 category '" + strCategory + "' 和 name '" + strName + "'"; } return(0); END1: return(nRet); ERROR1: return(-1); } finally { this.UnlockForRead(); } }
// 工作线程 public virtual void ThreadMain() { try { WaitHandle[] events = new WaitHandle[2]; events[0] = eventClose; events[1] = eventActive; while (true) { int index = 0; try { index = WaitHandle.WaitAny(events, PerTime, false); } catch (System.Threading.ThreadAbortException /*ex*/) { /* * // 调试用 * LibraryApplication.WriteWindowsLog("BatchTask俘获了ThreadAbortException异常", EventLogEntryType.Information); * */ this.App.Save(null, false); // 触发保存 this.App.WriteErrorLog("刚才是ThreadAbortException触发了配置文件保存"); break; } if (index == WaitHandle.WaitTimeout) { // 超时 eventActive.Reset(); Worker(); eventActive.Reset(); // 2013/11/23 只让堵住的时候发挥作用 } else if (index == 0) { break; } else { // 得到激活信号 eventActive.Reset(); Worker(); eventActive.Reset(); // 2013/11/23 只让堵住的时候发挥作用 } // 是否循环? if (this.Loop == false) { break; } } this.ManualStart = false; // 这个变量只在一轮处理中管用 } catch (Exception ex) { string strErrorText = "BatchTask工作线程出现异常: " + ExceptionUtil.GetDebugText(ex); try { this.App.WriteErrorLog(strErrorText); this.AppendResultText(strErrorText + "\r\n"); } catch { LibraryApplication.WriteWindowsLog(strErrorText); } } finally { // 2009/7/16 移动到这里 try { eventFinished.Set(); eventStarted.Set(); // 2017/8/23 } catch (ObjectDisposedException) // 2016/4/19 { } // 2009/7/16 新增 // this.m_bClosed = true; this.Stopped = true; } }
public ArriveMonitor(LibraryApplication app, string strName) : base(app, strName) { this.Loop = true; }
// 将读者记录数据从XML格式转换为HTML格式 // parameters: // strRecPath 读者记录路径 2009/10/18 // strLibraryCode 读者记录所从属的读者库的馆代码 // strResultType 细节格式。为了 '|' 间隔的若干名称字符串 public int ConvertReaderXmlToHtml( SessionInfo sessioninfo, string strCsFileName, string strRefFileName, string strLibraryCode, string strXml, string strRecPath, OperType opertype, string[] saBorrowedItemBarcode, string strCurrentItemBarcode, string strResultType, out string strResult, out string strError) { strResult = ""; strError = ""; int nRet = 0; // TODO: ParseTwoPart string strSubType = ""; nRet = strResultType.IndexOf(":"); if (nRet != -1) { strSubType = strResultType.Substring(nRet + 1).Trim(); } LibraryApplication app = this; // 转换为html格式 Assembly assembly = null; nRet = app.GetXml2HtmlAssembly( strCsFileName, strRefFileName, app.BinDir, out assembly, out strError); if (nRet == -1) { goto ERROR1; } // 得到Assembly中Converter派生类Type Type entryClassType = ScriptManager.GetDerivedClassType( assembly, "DigitalPlatform.LibraryServer.ReaderConverter"); if (entryClassType == null) { strError = "从DigitalPlatform.LibraryServer.ReaderConverter派生的类 type entry not found"; goto ERROR1; } // new一个Converter派生对象 ReaderConverter obj = (ReaderConverter)entryClassType.InvokeMember(null, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null); // 为Converter派生类设置参数 // obj.MainForm = this; obj.BorrowedItemBarcodes = saBorrowedItemBarcode; obj.CurrentItemBarcode = strCurrentItemBarcode; obj.OperType = opertype; obj.App = app; obj.SessionInfo = sessioninfo; obj.RecPath = strRecPath; obj.LibraryCode = strLibraryCode; // 2012/9/8 obj.Formats = strSubType.Replace("|", ","); // 调用关键函数Convert try { strResult = obj.Convert(strXml); } catch (Exception ex) { strError = "脚本执行时抛出异常: " + ExceptionUtil.GetDebugText(ex); goto ERROR1; } return(0); ERROR1: return(-1); }
// 设置历史字符串的某位的 'y' 状态 public static int SetNotified( LibraryApplication app, string strBodyType, int nTimeIndex, ref string strHistory, out string strError) { strError = ""; Debug.Assert(nTimeIndex >= 0, ""); int nExtendCount = 0; // 扩展接口的个数 if (app.m_externalMessageInterfaces != null) nExtendCount = app.m_externalMessageInterfaces.Count; int nSegmentLength = nExtendCount + 2; // 每个小部分的长度 int index = -1; // 0: dpmail; 1: email; >=2: 其他扩充的消息接口方式 if (strBodyType == "dpmail") { index = 0; } else if (strBodyType == "email") { index = 1; } else { MessageInterface external_interface = app.GetMessageInterface(strBodyType); if (external_interface == null) { strError = "不能识别的 message type '" + strBodyType + "'"; return -1; } index = app.m_externalMessageInterfaces.IndexOf(external_interface); if (index == -1) { strError = "external_interface (type '" + external_interface.Type + "') 没有在 m_externalMessageInterfaces 数组中找到"; return -1; } index += 2; } // 计算在整体中的偏移 index = (nSegmentLength * nTimeIndex) + index; if (strHistory.Length < index + 1) strHistory = strHistory.PadRight(index + 1, 'n'); strHistory = strHistory.Remove(index, 1); strHistory = strHistory.Insert(index, "y"); return 1; }
// 把实体记录借阅信息详细化 // parameters: // strEntityRecPath 册记录路径。如果本参数值为空,则表示希望通过strItemBarcode参数来找到册记录 // return: // -1 error // 0 册条码号没有找到对应的册记录 // 1 成功 int ModifyEntityRecord( // RmsChannelCollection Channels, RmsChannel channel, string strEntityRecPath, string strItemBarcode, string strReaderBarcode, string strBorrowDate, string strBorrowPeriod, out string strError) { strError = ""; int nRet = 0; long lRet = 0; int nRedoCount = 0; if (String.IsNullOrEmpty(strItemBarcode) == true) { strError = "strItemBarcode参数不能为空"; return(-1); } // RmsChannel channel = null; REDO_CHANGE: string strOutputItemRecPath = ""; byte[] item_timestamp = null; string strItemXml = ""; List <string> aPath = null; #if NO if (channel == null) { channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return(-1); } } #endif if (String.IsNullOrEmpty(strEntityRecPath) == false) { string strStyle = "content,data,metadata,timestamp,outputpath"; string strMetaData = ""; lRet = channel.GetRes(strEntityRecPath, strStyle, out strItemXml, out strMetaData, out item_timestamp, out strOutputItemRecPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { return(0); } strError = "ModifyEntityRecord()通过册记录路径 '" + strEntityRecPath + "' 读入册记录时发生错误: " + strError; return(-1); } } else { // 从册条码号获得册记录 // 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) { // 册条码号不存在也是需要修复的情况之一。 return(0); } if (nRet == -1) { strError = "ModifyEntityRecord()读入册记录时发生错误: " + strError; return(-1); } if (aPath.Count > 1) { // TODO: 需要将入围的记录全部提取出来,然后看borrower符合读者证条码号的那一条(或者多条?) // 可以参考UpgradeDt1000Loan中的SearchEntityRecord()函数 /* * strError = "因册条码号 '" + strItemBarcode + "' 检索命中多条册记录: " + StringUtil.MakePathList(aPath) + ",修改册记录的操作ModifyEntityRecord()无法进行"; * return -1; * */ int nSuccessCount = 0; string strTempError = ""; // 递归 for (int i = 0; i < aPath.Count; i++) { string strTempPath = aPath[i]; if (String.IsNullOrEmpty(strTempPath) == true) { Debug.Assert(false, ""); continue; } // return: // -1 error // 0 册条码号没有找到对应的册记录 // 1 成功 nRet = ModifyEntityRecord( // Channels, channel, strTempPath, strItemBarcode, strReaderBarcode, strBorrowDate, strBorrowPeriod, out strError); if (nRet == -1 && nSuccessCount == 0) { if (String.IsNullOrEmpty(strTempError) == false) { strTempError += "; "; } strTempError += "试探册记录 '" + strTempPath + "' 时发生错误: " + strError; } if (nRet == 1) { // 改为存储成功信息 if (nSuccessCount == 0) { strTempError = ""; } if (String.IsNullOrEmpty(strTempError) == false) { strTempError += "; "; } strTempError += strTempPath; nSuccessCount++; } } if (nSuccessCount > 0) { strError = "册条码号 '" + strItemBarcode + "' 检索命中" + aPath.Count.ToString() + "条册记录: " + StringUtil.MakePathList(aPath) + ",后面对它们进行了逐条试探,有 " + nSuccessCount.ToString() + " 条记录符合预期的要求,册中借阅信息得到增强。借阅信息得到增强的册记录路径如下: " + strTempError; return(1); } else { strError = "册条码号 '" + strItemBarcode + "' 检索命中" + aPath.Count.ToString() + "条册记录: " + StringUtil.MakePathList(aPath) + ",后面对它们进行了逐条试探,但是没有一条记录符合预期的要求。试探过程报错如下: " + strTempError; return(-1); } /* * result.Value = -1; * result.ErrorInfo = "册条码号为 '" + strItemBarcode + "' 的册记录有 " + aPath.Count.ToString() + " 条,无法进行修复操作。请在附加册记录路径后重新提交修复操作。"; * result.ErrorCode = ErrorCode.ItemBarcodeDup; * * aDupPath = new string[aPath.Count]; * aPath.CopyTo(aDupPath); * return result; * */ } 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; return(-1); } // 校验册条码号参数是否和XML记录中完全一致 string strTempItemBarcode = DomUtil.GetElementText(itemdom.DocumentElement, "barcode"); if (strItemBarcode != strTempItemBarcode) { strError = "修改册记录ModifyEntityRecord()操作被拒绝。因册条码号参数 '" + strItemBarcode + "' 和册记录中<barcode>元素内的册条码号值 '" + strTempItemBarcode + "' 不一致。"; return(-1); } // 看看册记录中是否有指回读者记录的链 string strBorrower = DomUtil.GetElementText(itemdom.DocumentElement, "borrower"); if (strBorrower != strReaderBarcode) { // strError = "ModifyEntityRecord()操作被拒绝。您所请求要修复的链,本是一条完整正确的链。可直接进行普通还书操作。"; strError = "修改册记录ModifyEntityRecord()操作被拒绝。因册记录 " + strOutputItemRecPath + " 中的[borrower]值 '" + strBorrower + "' 和发源(来找册条码号 '" + strItemBarcode + "')的读者证条码号 '" + strReaderBarcode + "' 不一致,不能构成一条完整正确的链。请及时排除此故障。"; return(-1); } // 2007/1/1注:应当看看记录中<borrower>元素是否有内容才改写<borrowDate>和<borrowPeriod>元素。 DomUtil.SetElementText(itemdom.DocumentElement, "borrowDate", strBorrowDate); DomUtil.SetElementText(itemdom.DocumentElement, "borrowPeriod", strBorrowPeriod); #if NO if (channel == null) { channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return(-1); } } #endif 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) { if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { nRedoCount++; if (nRedoCount > 10) { strError = "ModifyEntityRecord()写回册记录的时候,遇到时间戳冲突,并因此重试10次,仍失败..."; return(-1); } goto REDO_CHANGE; } return(-1); } // end of 写回册记录失败 return(1); }
// 构造函数 public ItemDatabase(LibraryApplication app) { this.App = app; }
void RenderBorrow( LibraryApplication app, SessionInfo sessioninfo, XmlDocument dom) { string strReaderType = DomUtil.GetElementText(dom.DocumentElement, "readerType"); // 获得日历 string strError = ""; Calendar calendar = null; int nRet = app.GetReaderCalendar(strReaderType, out calendar, out strError); if (nRet == -1) { this.SetBorrowDebugInfo(strError); calendar = null; } // 借阅的册 PlaceHolder borrowinfo = (PlaceHolder)this.FindControl("borrowinfo"); // 清空集合 this.BorrowBarcodes = new List<string>(); string strReaderBarcode = DomUtil.GetElementText(dom.DocumentElement, "barcode"); XmlNodeList nodes = dom.DocumentElement.SelectNodes("borrows/borrow"); this.BorrowLineCount = nodes.Count; for (int i = 0; i < nodes.Count; i++) { PlaceHolder line = (PlaceHolder)borrowinfo.FindControl("borrowinfo_line" + Convert.ToString(i)); if (line == null) { Control insertpos = borrowinfo.FindControl("borrowinfo_insertpos"); line = NewBorrowLine(insertpos.Parent, i, insertpos); // this.BorrowLineCount++; } line.Visible = true; LiteralControl left = (LiteralControl)line.FindControl("borrowinfo_line" + Convert.ToString(i) + "left"); CheckBox checkbox = (CheckBox)line.FindControl("borrowinfo_line" + Convert.ToString(i) + "checkbox"); LiteralControl right = (LiteralControl)line.FindControl("borrowinfo_line" + Convert.ToString(i) + "right"); XmlNode node = nodes[i]; string strBarcode = DomUtil.GetAttr(node, "barcode"); // 添加到集合 this.BorrowBarcodes.Add(strBarcode); string strNo = DomUtil.GetAttr(node, "no"); string strBorrowDate = DomUtil.GetAttr(node, "borrowDate"); string strPeriod = DomUtil.GetAttr(node, "borrowPeriod"); string strOperator = DomUtil.GetAttr(node, "operator"); string strRenewComment = DomUtil.GetAttr(node, "renewComment"); string strColor = "bgcolor=#ffffff"; string strOverDue = ""; // string strError = ""; // 检查超期情况。 // return: // -1 数据格式错误 // 0 没有发现超期 // 1 发现超期 strError中有提示信息 // 2 已经在宽限期内,很容易超期 2009/3/13 nRet = app.CheckPeriod( calendar, strBorrowDate, strPeriod, out strError); if (nRet == -1) strOverDue = strError; else { strOverDue = strError; // 其他无论什么情况都显示出来 } string strResult = ""; string strClass = " class='roundcontentdark' "; if ((i % 2) == 1) strClass = " class='roundcontentlight' "; strResult += "<tr " + strClass + strColor + " nowrap><td nowrap>"; // 左 left.Text = strResult; // checkbox // checkbox.Text = Convert.ToString(i + 1); // 右开始 strResult = " "; strResult += "<a href='book.aspx?barcode=" + strBarcode + "&borrower=" + strReaderBarcode + "'>" + strBarcode + "</a></td>"; // 获得摘要 string strSummary = ""; string strBiblioRecPath = ""; LibraryServerResult result = app.GetBiblioSummary( sessioninfo, strBarcode, null, null, out strBiblioRecPath, out strSummary); if (result.Value == -1 || result.Value == 0) strSummary = result.ErrorInfo; strResult += "<td width='50%'>" + strSummary + "</td>"; strResult += "<td nowrap align='right'>" + strNo + "</td>"; strResult += "<td nowrap>" + ItemConverter.LocalTime(strBorrowDate) + "</td>"; strResult += "<td nowrap>" + strPeriod + "</td>"; strResult += "<td nowrap>" + strOperator + "</td>"; strResult += "<td>" + strOverDue + "</td>"; strResult += "<td>" + strRenewComment.Replace(";", "<br/>") + "</td>"; strResult += "</tr>"; right.Text = strResult; } // 把多余的行隐藏起来 for (int i = nodes.Count; ; i++) { PlaceHolder line = (PlaceHolder)borrowinfo.FindControl("borrowinfo_line" + Convert.ToString(i)); if (line == null) break; line.Visible = false; } }
// 初始化对象 public int Initial( LibraryApplication app, string strDirectory, out string strError) { strError = ""; int nRet = 0; this.App = app; this.Close(); // 2013/12/1 ////Debug.WriteLine("begin write lock 4"); this.m_lock.AcquireWriterLock(m_nLockTimeout); try { m_strDirectory = strDirectory; PathUtil.CreateDirIfNeed(m_strDirectory); // 2013/6/16 nRet = this.VerifyLogFiles(true, out strError); if (nRet == -1) { this.App.WriteErrorLog("校验操作日志时出错: " + strError); return -1; } if (nRet == 1) { this.App.WriteErrorLog("校验操作日志时发现错误,已经自动修复:" + strError); } // 将全部小文件合并到大文件 // return: // -1 运行出错 // 0 没有错误 // 1 有错误 nRet = MergeTempLogFiles(true, out strError); if (nRet == -1) { this.App.WriteErrorLog("合并临时日志文件时出错: " + strError); return -1; } if (nRet == 1) { this.App.WriteErrorLog("合并临时日志文件时发现错误,已经自动修复:" + strError); } nRet = PrepareSpareOperLogFile(out strError); if (nRet == -1) return -1; Debug.Assert(this.m_streamSpare != null, ""); // return: // -1 出错。 // 0 普通情况,不用恢复 // 1 已恢复 nRet = DoRecover(out strError); if (nRet == -1) { // 从备用文件中恢复,失败 return -1; } // 文件指针需处于迎接异常的状态 this.m_streamSpare.Seek(0, SeekOrigin.Begin); // this._bSmallFileMode = true; // 测试 return 0; } finally { this.m_lock.ReleaseWriterLock(); ////Debug.WriteLine("end write lock 4"); } }
// 判断是否超过保留期限 // return: // -1 error // 0 没有超过 // 1 已经超过 int CheckeOutOfReservation( Calendar calendar, XmlDocument queue_rec_dom, out string strError) { strError = ""; string strState = DomUtil.GetElementText(queue_rec_dom.DocumentElement, "state"); // 对通知完成后的记录, 循环中不必处理 if (StringUtil.IsInList("outof", strState) == true) { return(0); } string strNotifyDate = DomUtil.GetElementText(queue_rec_dom.DocumentElement, "notifyDate"); /* * string strItemBarcode = DomUtil.GetElementText(queue_rec_dom.DocumentElement, * "itemBarcode"); * string strReaderBarcode = DomUtil.GetElementText(queue_rec_dom.DocumentElement, * "readerBarcode"); * */ // 解析期限值 string strPeriodUnit = ""; long lPeriodValue = 0; int nRet = LibraryApplication.ParsePeriodUnit( this.App.ArrivedReserveTimeSpan, out lPeriodValue, out strPeriodUnit, out strError); if (nRet == -1) { strError = "预约保留期限 值 '" + this.App.ArrivedReserveTimeSpan + "' 格式错误: " + strError; return(-1); } // DateTime notifydate; try { notifydate = DateTimeUtil.FromRfc1123DateTimeString(strNotifyDate); } catch { strError = "通知日期值 '" + strNotifyDate + "' 格式错误"; return(-1); } DateTime timeEnd = DateTime.MinValue; nRet = LibraryApplication.GetOverTime( calendar, notifydate, lPeriodValue, strPeriodUnit, out timeEnd, out strError); if (nRet == -1) { strError = "计算保留期过程发生错误: " + strError; return(-1); } DateTime now = this.App.Clock.UtcNow; // DateTime.UtcNow; // 正规化时间 nRet = LibraryApplication.RoundTime(strPeriodUnit, ref now, out strError); if (nRet == -1) { return(-1); } TimeSpan delta = now - timeEnd; long lDelta = 0; nRet = LibraryApplication.ParseTimeSpan( delta, strPeriodUnit, out lDelta, out strError); if (nRet == -1) { return(-1); } if (lDelta > 0) { return(1); } return(0); }
// 处理一条记录 int DoOneRecord( long lPeriodValue, string strPeriodUnit, string strPath, string strRecXml, byte[] baTimeStamp, out string strError) { strError = ""; long lRet = 0; int nRet = 0; XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strRecXml); } catch (Exception ex) { strError = "装载XML到DOM出错: " + ex.Message; return(-1); } string strDate = DomUtil.GetElementText(dom.DocumentElement, "date"); bool bDelete = false; // DateTime date; try { date = DateTimeUtil.FromRfc1123DateTimeString(strDate); } catch { strError = "记录 " + strPath + " 消息日期值 '" + strDate + "' 格式错误"; this.App.WriteErrorLog(strError); // 注意仍然要删除 bDelete = true; goto DO_DELETE; } // 正规化时间date nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref date, out strError); if (nRet == -1) { strError = "正规化date时间 " + date.ToString() + " (时间单位: " + strPeriodUnit + ") 时出错: " + strError; return(-1); } DateTime now = this.App.Clock.UtcNow; // DateTime.UtcNow; // 正规化时间now nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref now, out strError); if (nRet == -1) { strError = "正规化now时间 " + now.ToString() + " (时间单位: " + strPeriodUnit + ") 时出错: " + strError; return(-1); } TimeSpan delta = now - date; long lDelta = 0; nRet = LibraryApplication.ParseTimeSpan( delta, strPeriodUnit, out lDelta, out strError); if (nRet == -1) { return(-1); } if (lDelta >= lPeriodValue) { bDelete = true; } DO_DELETE: if (bDelete == true) { RmsChannel channel = this.RmsChannels.GetChannel(this.App.WsUrl); byte[] output_timestamp = null; lRet = channel.DoDeleteRes( strPath, baTimeStamp, out output_timestamp, out strError); if (lRet == -1) { // 可以这次不删除,以后还有机会 strError = "删除记录 " + strPath + "时出错: " + strError; return(-1); } // 这个指标没有按分馆来计算 if (this.App.Statis != null) { this.App.Statis.IncreaseEntryValue( "", "消息监控", "删除过期消息条数", 1); } } return(0); }
// 获得读者类型 // return: // -1 出错 // 0 没有找到读者记录 // 1 找到 int GetReaderType(string strReaderBarcode, out string strReaderType, out string strError) { strError = ""; strReaderType = ""; if (string.IsNullOrEmpty(strReaderBarcode) == true) { strError = "strReaderBarcode 不能为空"; return(-1); } RmsChannel channel = this.RmsChannels.GetChannel(this.App.WsUrl); if (channel == null) { strError = "get channel error"; return(-1); } // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; int nRet = this.App.GetReaderRecXml( // this.RmsChannels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; return(0); } if (nRet == -1) { strError = "读入读者记录时发生错误: " + strError; return(-1); } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; return(-1); } strReaderType = DomUtil.GetElementText(readerdom.DocumentElement, "readerType"); return(1); }
// 给读者记录里加上预约到书后超期不取的状态 int AddReaderOutOfReservationInfo( // RmsChannelCollection channels, RmsChannel channel, string strReaderBarcode, string strItemBarcode, string strNotifyDate, out string strError) { strError = ""; int nRet = 0; long lRet = 0; int nRedoCount = 0; REDO_MEMO: // 加读者记录锁 #if DEBUG_LOCK_READER this.App.WriteErrorLog("AddReaderOutOfReservationInfo 开始为读者加写锁 '" + strReaderBarcode + "'"); #endif this.App.ReaderLocks.LockForWrite(strReaderBarcode); try // 读者记录锁定范围开始 { // 读入读者记录 string strReaderXml = ""; string strOutputReaderRecPath = ""; byte[] reader_timestamp = null; nRet = this.App.GetReaderRecXml( // channels, channel, strReaderBarcode, out strReaderXml, out strOutputReaderRecPath, out reader_timestamp, out strError); if (nRet == 0) { strError = "读者证条码号 '" + strReaderBarcode + "' 不存在"; return(-1); } if (nRet == -1) { strError = "读入读者记录时发生错误: " + strError; return(-1); } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strReaderXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入XML DOM时发生错误: " + strError; return(-1); } XmlNode root = readerdom.DocumentElement.SelectSingleNode("outofReservations"); if (root == null) { root = readerdom.CreateElement("outofReservations"); readerdom.DocumentElement.AppendChild(root); } // 累计次数 string strCount = DomUtil.GetAttr(root, "count"); if (String.IsNullOrEmpty(strCount) == true) { strCount = "0"; } int nCount = 0; try { nCount = Convert.ToInt32(strCount); } catch { } nCount++; DomUtil.SetAttr(root, "count", nCount.ToString()); // 追加<request>元素 XmlNode request = readerdom.CreateElement("request"); root.AppendChild(request); DomUtil.SetAttr(request, "itemBarcode", strItemBarcode); DomUtil.SetAttr(request, "notifyDate", strNotifyDate); byte[] output_timestamp = null; string strOutputPath = ""; #if NO RmsChannel channel = channels.GetChannel(this.App.WsUrl); if (channel == null) { strError = "get channel error"; return(-1); } #endif // 写回读者记录 lRet = channel.DoSaveTextRes(strOutputReaderRecPath, readerdom.OuterXml, false, "content", // ,ignorechecktimestamp reader_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { nRedoCount++; if (nRedoCount > 10) { strError = "写回读者记录的时候,遇到时间戳冲突,并因此重试10次,仍失败..."; return(-1); } goto REDO_MEMO; } return(-1); } } // 读者记录锁定范围结束 finally { this.App.ReaderLocks.UnlockForWrite(strReaderBarcode); #if DEBUG_LOCK_READER this.App.WriteErrorLog("AddReaderOutOfReservationInfo 结束为读者加写锁 '" + strReaderBarcode + "'"); #endif } return(0); }
// 去除册记录中过时的预约信息 // 册记录中<location>需要去掉#reservation,相关<request>元素也需要删除 // 锁定:本函数对EntityLocks加了锁定 int RemoveEntityReservationInfo(string strItemBarcode, string strReaderBarcode, out string strError) { strError = ""; int nRet = 0; if (String.IsNullOrEmpty(strItemBarcode) == true) { strError = "册条码号不能为空。"; return(-1); } if (String.IsNullOrEmpty(strReaderBarcode) == true) { strError = "读者证条码号不能为空。"; return(-1); } RmsChannel channel = this.RmsChannels.GetChannel(this.App.WsUrl); if (channel == null) { // text-level: 内部错误 strError = "get channel error"; return(-1); } // 加册记录锁 this.App.EntityLocks.LockForWrite(strItemBarcode); try // 册记录锁定范围开始 { // 从册条码号获得册记录 int nRedoCount = 0; REDO_CHANGE: List <string> aPath = null; string strItemXml = ""; byte[] item_timestamp = null; string strOutputItemRecPath = ""; // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.App.GetItemRecXml( // this.RmsChannels, channel, strItemBarcode, out strItemXml, 100, out aPath, out item_timestamp, out strError); if (nRet == 0) { strError = "册条码号 '" + strItemBarcode + "' 不存在"; return(-1); } if (nRet == -1) { strError = "读入册记录时发生错误: " + strError; return(-1); } if (aPath.Count > 1) { strError = "册条码号为 '" + strItemBarcode + "' 的册记录有 " + aPath.Count.ToString() + " 条,无法进行修改册记录的操作。"; return(-1); } 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; return(-1); } // 修改册记录 // 册记录中<location>需要去掉#reservation,相关<request>元素也需要删除 string strLocation = DomUtil.GetElementText(itemdom.DocumentElement, "location"); // StringUtil.RemoveFromInList("#reservation", true, ref strLocation); strLocation = StringUtil.GetPureLocationString(strLocation); DomUtil.SetElementText(itemdom.DocumentElement, "location", strLocation); XmlNode nodeRequest = itemdom.DocumentElement.SelectSingleNode("reservations/request[@reader='" + strReaderBarcode + "']"); if (nodeRequest != null) { nodeRequest.ParentNode.RemoveChild(nodeRequest); } #if NO RmsChannel channel = this.RmsChannels.GetChannel(this.App.WsUrl); #endif // 写回册记录 byte[] output_timestamp = null; string strOutputPath = ""; long lRet = channel.DoSaveTextRes(strOutputItemRecPath, itemdom.OuterXml, false, "content", // ,ignorechecktimestamp item_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { nRedoCount++; if (nRedoCount > 10) { strError = "写回册记录的时候,遇到时间戳冲突,并因此重试10次,仍失败..."; return(-1); } goto REDO_CHANGE; } } } // 册记录锁定范围结束 finally { // 解册记录锁 this.App.EntityLocks.UnlockForWrite(strItemBarcode); } return(0); }
// 是否全部订购信息片断中的馆藏地点都在当前用户管辖之下? // 那些没有名字的(馆藏地点)分配事项,算在分馆用户的管辖范围以外。没有名字的馆藏地点,在订购时视为地点未定 // return: // -1 出错 // 0 不是全部都在管辖范围内 // 1 都在管辖范围内 int IsAllOrderControlled(XmlNode nodeOrderInfo, string strLibraryCodeList, out string strError) { strError = ""; if (SessionInfo.IsGlobalUser(strLibraryCodeList) == true) { return(1); } // 对新提交的记录中的每个订购片断进行循环 XmlNodeList nodes = nodeOrderInfo.SelectNodes("*"); foreach (XmlNode node in nodes) { string strDistribute = DomUtil.GetElementText(node, "distribute"); if (string.IsNullOrEmpty(strDistribute) == true) { continue; } // 观察一个馆藏分配字符串,看看是否在当前用户管辖范围内 // return: // -1 出错 // 0 超过管辖范围。strError中有解释 // 1 在管辖范围内 int nRet = DistributeInControlled(strDistribute, strLibraryCodeList, out strError); if (nRet == -1) { return(-1); } if (nRet == 0) { return(0); } #if NO LocationCollcetion locations = new LocationCollcetion(); int nRet = locations.Build(strDistribute, out strError); if (nRet == -1) { strError = "馆藏分配字符串 '" + strDistribute + "' 格式不正确"; return(-1); } foreach (Location location in locations) { if (string.IsNullOrEmpty(location.Name) == true) { continue; } string strLibraryCode = ""; string strPureName = ""; // 解析 LibraryApplication.ParseCalendarName(location.Name, out strLibraryCode, out strPureName); if (StringUtil.IsInList(strLibraryCode, strLibraryCodeList) == false) { strError = "馆代码 '" + strLibraryCode + "' 不在范围 '" + strLibraryCodeList + "' 内"; return(0); } } #endif } return(1); }
// 将两个订购XML片断合并 // 当旧的和新的都是全管辖范围内,就允许新的全部替换旧的;否则只允许替换<distribute>元素内容 // parameters: // strLibraryCodeList 当前用户管辖的分馆代码列表 // strMergedXml [out]范围订购<root>元素的InnerXml // return: // -1 出错 // 0 正常 // 1 发生了超越范围的修改 public static int MergeOrderNode(XmlNode exist_node, XmlNode new_node, string strLibraryCodeList, out string strMergedXml, out string strError) { strError = ""; strMergedXml = ""; int nRet = 0; Debug.Assert(SessionInfo.IsGlobalUser(strLibraryCodeList) == false, "全局用户不应调用函数 MergeOrderNode()"); string strExistDistribute = DomUtil.GetElementText(exist_node, "distribute"); string strNewDistribute = DomUtil.GetElementText(new_node, "distribute"); bool bExistControlled = true; bool bNewControlled = true; if (string.IsNullOrEmpty(strExistDistribute) == false) { // 观察一个馆藏分配字符串,看看是否在当前用户管辖范围内 // return: // -1 出错 // 0 超过管辖范围。strError中有解释 // 1 在管辖范围内 nRet = DistributeInControlled(strExistDistribute, strLibraryCodeList, out strError); if (nRet == -1) { return(-1); } if (nRet == 0) { bExistControlled = false; } } if (string.IsNullOrEmpty(strNewDistribute) == false) { // 观察一个馆藏分配字符串,看看是否在当前用户管辖范围内 // return: // -1 出错 // 0 超过管辖范围。strError中有解释 // 1 在管辖范围内 nRet = DistributeInControlled(strNewDistribute, strLibraryCodeList, out strError); if (nRet == -1) { return(-1); } if (nRet == 0) { bNewControlled = false; } } if (bExistControlled == true && bNewControlled == true) { // 当旧的和新的都是全管辖范围内,就允许新的全部替换旧的 strMergedXml = new_node.InnerXml; return(0); } string strExistCopy = DomUtil.GetElementText(exist_node, "copy"); string strExistPrice = DomUtil.GetElementText(exist_node, "price"); string strChangedCopy = DomUtil.GetElementText(new_node, "copy"); string strChangedPrice = DomUtil.GetElementText(new_node, "price"); // 比较两个复本字符串 { ParseOldNewValue(strExistCopy, out string strExistOldValue, out string strExistNewValue); ParseOldNewValue(strChangedCopy, out string strChangedOldValue, out string strChangedNewValue); if (strExistOldValue != strChangedOldValue) { strError = "订购套数(方括号左边的部分)不允许修改。(原来='" + strExistCopy + "',新的='" + strChangedCopy + "')"; return(1); } // 检查验收套数的改变,是否正好和distribute字符串内的改变吻合 } // 比较两个价格字符串 { ParseOldNewValue(strExistPrice, out string strExistOldValue, out string strExistNewValue); ParseOldNewValue(strChangedPrice, out string strChangedOldValue, out string strChangedNewValue); // 避免用 == 判断。用 IsEqual 判断,可以把 CNY10.00 和 10.00 视作等同 if (PriceUtil.IsEqual(strExistOldValue, strChangedOldValue) == false) { strError = "订购价(方括号左边的部分)不允许修改。(原来='" + strExistPrice + "',新的='" + strChangedPrice + "')"; return(1); } if (PriceUtil.IsEqual(strExistNewValue, strChangedNewValue) == false) { strError = "验收价(方括号中的部分)不允许修改。(原来='" + strExistPrice + "',新的='" + strChangedPrice + "')"; return(1); } } LocationCollection new_locations = new LocationCollection(); nRet = new_locations.Build(strNewDistribute, out strError); if (nRet == -1) { strError = "馆藏分配字符串 '" + strNewDistribute + "' 格式不正确"; return(-1); } LocationCollection exist_locations = new LocationCollection(); nRet = exist_locations.Build(strExistDistribute, out strError); if (nRet == -1) { strError = "馆藏分配字符串 '" + strExistDistribute + "' 格式不正确"; return(-1); } if (exist_locations.Count != new_locations.Count) { strError = "馆藏分配事项个数发生了改变(原来=" + exist_locations.Count.ToString() + ",新的=" + new_locations.Count.ToString() + ")"; return(1); } for (int i = 0; i < exist_locations.Count; i++) { Location exist_location = exist_locations[i]; Location new_location = new_locations[i]; if (exist_location.Name != new_location.Name) { // 进一步检查是否馆代码部分改变了 // 解析 LibraryApplication.ParseCalendarName(exist_location.Name, out string strCode1, out string strPureName); LibraryApplication.ParseCalendarName(new_location.Name, out string strCode2, out strPureName); // 只要馆代码部分不改变即可 if (strCode1 != strCode2) { strError = "第 " + (i + 1).ToString() + " 个馆藏分配事项的名字(的馆代码部分)发生改变 (原来='" + exist_location.Name + "',新的='" + new_location.Name + "')"; return(1); } } if (exist_location.RefID != new_location.RefID) { // 解析 LibraryApplication.ParseCalendarName(exist_location.Name, out string strLibraryCode, out string strPureName); if (StringUtil.IsInList(strLibraryCode, strLibraryCodeList) == false) { strError = "馆代码 '" + strLibraryCode + "' 不在范围 '" + strLibraryCodeList + "' 内,不允许进行收登操作。"; return(1); } } } // 将旧的XML片断装入,只修改里面的三个元素值。这样可以保证三个元素以外的原记录内容不被修改 XmlDocument dom = new XmlDocument(); try { dom.LoadXml(exist_node.OuterXml); } catch (Exception ex) { strError = "exist_node.OuterXml装入XMLDOM失败: " + ex.Message; return(-1); } DomUtil.SetElementText(dom.DocumentElement, "copy", strChangedCopy); DomUtil.SetElementText(dom.DocumentElement, "price", strChangedPrice); DomUtil.SetElementText(dom.DocumentElement, "distribute", strNewDistribute); strMergedXml = dom.DocumentElement.InnerXml; return(0); }
public BatchTask(LibraryApplication app, string strName) { if (String.IsNullOrEmpty(strName) == true) this.Name = this.DefaultName; else this.Name = strName; this.App = app; this.RmsChannels.GUI = false; this.RmsChannels.AskAccountInfo -= new AskAccountInfoEventHandle(RmsChannels_AskAccountInfo); this.RmsChannels.AskAccountInfo += new AskAccountInfoEventHandle(RmsChannels_AskAccountInfo); Debug.Assert(this.App != null, ""); this.ProgressFileName = this.App.GetTempFileName("batch_progress"); // Path.GetTempFileName(); try { // 如果文件存在,就打开,如果文件不存在,就创建一个新的 m_stream = File.Open( this.ProgressFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); this.ProgressFileVersion = DateTime.Now.Ticks; } catch (Exception ex) { string strError = "打开或创建文件 '" + this.ProgressFileName + "' 发生错误: " + ex.Message; throw new Exception(strError); } m_stream.Seek(0, SeekOrigin.End); }
// 获得一种 body type 的全部通知字符 public static string GetNotifiedChars(LibraryApplication app, string strBodyType, string strHistory) { int nExtendCount = 0; // 扩展接口的个数 if (app.m_externalMessageInterfaces != null) nExtendCount = app.m_externalMessageInterfaces.Count; int nSegmentLength = nExtendCount + 3; // 原来是 2 // 每个小部分的长度 int index = -1; // 0: dpmail; 1: email; >=2: 其他扩充的消息接口方式 if (strBodyType == "dpmail") { index = 0; } else if (strBodyType == "email") { index = 1; } else if (strBodyType == "mq") { index = 2; } else { MessageInterface external_interface = app.GetMessageInterface(strBodyType); if (external_interface == null) { // strError = "不能识别的 message type '" + strBodyType + "'"; // return -1; return null; } index = app.m_externalMessageInterfaces.IndexOf(external_interface); if (index == -1) { // strError = "external_interface (type '" + external_interface.Type + "') 没有在 m_externalMessageInterfaces 数组中找到"; // return -1; return null; } index += 3; // 原来是 2 } string strResult = ""; for (int i = 0; i < strHistory.Length / nSegmentLength; i++) { int nStart = i * nSegmentLength; int nLength = nSegmentLength; if (nStart + nLength > strHistory.Length) nLength = strHistory.Length - nStart; string strSegment = strHistory.Substring(nStart, nLength); if (index < strSegment.Length) strResult += strSegment[index]; else strResult += 'n'; } return strResult; }