public async Task <byte[]> DefaultProcessPresent(ZServerChannel channel, BerTree request) { BerNode root = request.GetAPDuRoot(); // 解码Search请求包 int nRet = ZProcessor.Decode_PresentRequest( root, out PresentRequestInfo info, out string strError); if (nRet == -1) { goto ERROR1; } if (channel.EnsureProperty()._bInitialized == false) { return(null); } PresentGetRecordsEventArgs e = new PresentGetRecordsEventArgs(); if (this.PresentGetRecords == null) { // 模拟返回一条记录 e.Records = new List <RetrivalRecord>(); RetrivalRecord record = new RetrivalRecord(); // TODO: 准备数据 e.Records.Add(record); } else { e.Request = info; this.PresentGetRecords(channel, e); } // 编码Present响应包 nRet = ZProcessor.Encode_PresentResponse(info, e.Records, e.Diag, e.TotalCount, out byte[] baResponsePackage); if (nRet == -1) { goto ERROR1; } return(baResponsePackage); ERROR1: // TODO: 将错误原因写入日志 return(null); }
private static void Zserver_PresentGetRecords(object sender, PresentGetRecordsEventArgs e) { string strError = ""; int nCondition = 100; // (unspecified)error ZServerChannel zserver_channel = (ZServerChannel)sender; if (zserver_channel == null) { throw new ArgumentException("zserver_channel 为空"); } string strInstanceName = zserver_channel.EnsureProperty().GetKeyValue("i_n"); if (strInstanceName == null) { strError = "通道中 实例名 'i_n' 尚未初始化"; // ?? bug LibraryManager.Log?.Error(strError); goto ERROR1; } Instance instance = FindZ3950Instance(strInstanceName, out strError); if (instance == null) { if (string.IsNullOrEmpty(strError)) { strError = "实例名 '" + strInstanceName + "' 不存在(或实例没有启用 Z39.50 服务)"; } goto ERROR1; } if (instance.Running == false) { strError = "实例 '" + instance.Name + "' 正在维护中,暂时不能访问"; nCondition = 1019; // Init/AC: System not available due to maintenance goto ERROR1; } string strResultSetName = e.Request.m_strResultSetID; if (String.IsNullOrEmpty(strResultSetName) == true) { strResultSetName = "default"; } long lStart = e.Request.m_lResultSetStartPoint - 1; long lNumber = e.Request.m_lNumberOfRecordsRequested; int MAX_PRESENT_RECORD = 100; // 限制每次 present 的记录数量 if (lNumber > MAX_PRESENT_RECORD) { lNumber = MAX_PRESENT_RECORD; } DiagFormat diag = null; List <RetrivalRecord> records = new List <RetrivalRecord>(); string strUserName = zserver_channel.EnsureProperty().GetKeyValue("i_u"); string strPassword = zserver_channel.EnsureProperty().GetKeyValue("i_p"); LoginInfo login_info = BuildLoginInfo(strUserName, strPassword); LibraryChannel library_channel = instance.MessageConnection.GetChannel(login_info); zserver_channel.Tag = library_channel; try { // 全局结果集名 string resultset_name = MakeGlobalResultSetName(zserver_channel, strResultSetName); // TODO: timestamp 有必要获取么? ResultSetLoader loader = new ResultSetLoader(library_channel, resultset_name, "id,xml,timestamp") { Start = lStart, BatchSize = Math.Min(10, lNumber) }; int i = 0; int nSize = 0; foreach (DigitalPlatform.LibraryClient.localhost.Record dp2library_record in loader) { if (i >= lNumber) { break; } // 判断请求边界是否合法。放到循环里面的 i==0 时刻来做,是因为枚举器(loader)需要请求 dp2library 之后才能知道结果集大小 if (i == 0) { e.TotalCount = loader.TotalCount; if (lStart >= loader.TotalCount) { DiagFormat diag1 = null; ZProcessor.SetPresentDiagRecord(ref diag1, 13, // Present request out-of-range "Present 所请求的起始偏移位置 " + lStart + " 超过结果集中记录总数 " + loader.TotalCount); e.Diag = diag1; return; } if (lStart + lNumber > loader.TotalCount) { DiagFormat diag1 = null; ZProcessor.SetPresentDiagRecord(ref diag1, 13, // Present request out-of-range "Present 所请求的结束偏移位置 " + (lStart + lNumber) + " 超过结果集中记录总数 " + loader.TotalCount); e.Diag = diag1; return; } } { // 解析出数据库名和ID string strDbName = dp2StringUtil.GetDbName(dp2library_record.Path); string strRecID = dp2StringUtil.GetRecordID(dp2library_record.Path); // 如果取得的是xml记录,则根元素可以看出记录的marc syntax,进一步可以获得oid; // 如果取得的是MARC格式记录,则需要根据数据库预定义的marc syntax来看出oid了 // string strMarcSyntaxOID = GetMarcSyntaxOID(instance, strDbName); // string strMarcSyntaxOID = GetMarcSyntaxOID(dp2library_record); RetrivalRecord record = new RetrivalRecord { m_strDatabaseName = strDbName }; // 根据书目库名获得书目库属性对象 // TODO: 这里可以考虑 cache BiblioDbProperty prop = instance.zhost.GetDbProperty( strDbName, false); int nRet = GetIso2709Record(dp2library_record, e.Request.m_elementSetNames, prop != null ? prop.AddField901 : false, prop != null ? prop.RemoveFields : "997", zserver_channel.EnsureProperty().MarcRecordEncoding, out string strMarcSyntaxOID, out byte[] baIso2709, out strError); /* * // 测试记录群中包含诊断记录 * if (i == 1) * { * nRet = -1; * strError = "测试获取记录错误"; * } */ if (nRet == -1) { record.m_surrogateDiagnostic = new DiagFormat { m_strDiagSetID = "1.2.840.10003.4.1", m_nDiagCondition = 14, // system error in presenting records m_strAddInfo = strError }; } else if (nRet == 0) { record.m_surrogateDiagnostic = new DiagFormat { m_strDiagSetID = "1.2.840.10003.4.1", m_nDiagCondition = 1028, // record deleted m_strAddInfo = strError }; } else if (String.IsNullOrEmpty(strMarcSyntaxOID) == true) { // 根据数据库名无法获得marc syntax oid。可能是虚拟库检索命中记录所在的物理库没有在 capo.xml 中配置。 record.m_surrogateDiagnostic = new DiagFormat { m_strDiagSetID = "1.2.840.10003.4.1", m_nDiagCondition = 227, // No data available in requested record syntax // 239? // m_strAddInfo = "根据数据库名 '" + strDbName + "' 无法获得 marc syntax oid" m_strAddInfo = "根据书目记录 '" + dp2library_record.Path + "' 的 MARCXML 无法获得 marc syntax oid" }; } else { record.m_external = new External { m_strDirectRefenerce = strMarcSyntaxOID, m_octectAligned = baIso2709 }; } // TODO: 测试观察这里的 size 增长情况 nSize += record.GetPackageSize(); if (i == 0) { // 连一条记录也放不下 if (nSize > zserver_channel.EnsureProperty().ExceptionalRecordSize) { Debug.Assert(diag == null, ""); ZProcessor.SetPresentDiagRecord(ref diag, 17, // record exceeds Exceptional_record_size "记录尺寸 " + nSize.ToString() + " 超过 Exceptional_record_size " + zserver_channel.EnsureProperty().ExceptionalRecordSize.ToString()); lNumber = 0; break; } } else { if (nSize >= zserver_channel.EnsureProperty().PreferredMessageSize) { // TODO: 记入日志? // 调整返回的记录数 lNumber = i; break; } } records.Add(record); } i++; // 2018/9/28 // 防范性编程 // TODO: 还可以通过时间长度来控制。超过一定时间,就抛出异常 if (i > MAX_PRESENT_RECORD) { throw new Exception("Zserver_PresentGetRecords() 中获取记录的循环超过极限数量 " + MAX_PRESENT_RECORD + "(此时 lNumber=" + lNumber + ")"); } } } catch (ChannelException ex) { // 指定的结果集没有找到 if (ex.ErrorCode == DigitalPlatform.LibraryClient.localhost.ErrorCode.NotFound) { nCondition = 30; // Specified result set does not exist strError = ex.Message; goto ERROR1; } strError = "获取结果集时出现异常(ChannelException): " + ex.Message; goto ERROR1; } catch (Exception ex) { strError = "获取结果集时出现异常: " + ex.Message; goto ERROR1; } finally { zserver_channel.Tag = null; instance.MessageConnection.ReturnChannel(library_channel); } e.Records = records; e.Diag = diag; return; ERROR1: { DiagFormat diag1 = null; ZProcessor.SetPresentDiagRecord(ref diag1, nCondition, strError); e.Diag = diag1; return; } }
private static void Zserver_PresentGetRecords(object sender, PresentGetRecordsEventArgs e) { string strError = ""; ZServerChannel zserver_channel = (ZServerChannel)sender; string strInstanceName = zserver_channel.SetProperty().GetKeyValue("i_n"); if (strInstanceName == null) { strError = "通道中 实例名 '" + strInstanceName + "' 尚未初始化"; ZManager.Log.Error(strError); goto ERROR1; } Instance instance = FindInstance(strInstanceName); if (instance == null) { strError = "实例名 '" + strInstanceName + "' 不存在"; goto ERROR1; } string strResultSetName = e.Request.m_strResultSetID; if (String.IsNullOrEmpty(strResultSetName) == true) { strResultSetName = "default"; } long lStart = e.Request.m_lResultSetStartPoint - 1; long lNumber = e.Request.m_lNumberOfRecordsRequested; int MAX_PRESENT_RECORD = 100; // 限制每次 present 的记录数量 if (lNumber > MAX_PRESENT_RECORD) { lNumber = MAX_PRESENT_RECORD; } DiagFormat diag = null; List <RetrivalRecord> records = new List <RetrivalRecord>(); string strUserName = zserver_channel.SetProperty().GetKeyValue("i_u"); string strPassword = zserver_channel.SetProperty().GetKeyValue("i_p"); LoginInfo login_info = new LoginInfo { UserName = strUserName, Password = strPassword }; LibraryChannel library_channel = instance.MessageConnection.GetChannel(login_info); try { // 全局结果集名 string resultset_name = MakeGlobalResultSetName(zserver_channel, strResultSetName); ResultSetLoader loader = new ResultSetLoader(library_channel, resultset_name, "id,xml,timestamp") { Start = lStart, BatchSize = Math.Min(10, lNumber) }; int i = 0; int nSize = 0; foreach (DigitalPlatform.LibraryClient.localhost.Record dp2library_record in loader) { if (i >= lNumber) { break; } if (i == 0) { e.TotalCount = loader.TotalCount; if (lStart >= loader.TotalCount) { DiagFormat diag1 = null; ZProcessor.SetPresentDiagRecord(ref diag1, 13, // Present request out-of-range "Present 所请求的起始偏移位置 " + lStart + " 超过结果集中记录总数 " + loader.TotalCount); e.Diag = diag1; return; } } { // 解析出数据库名和ID string strDbName = dp2StringUtil.GetDbName(dp2library_record.Path); string strRecID = dp2StringUtil.GetRecordID(dp2library_record.Path); // 如果取得的是xml记录,则根元素可以看出记录的marc syntax,进一步可以获得oid; // 如果取得的是MARC格式记录,则需要根据数据库预定义的marc syntax来看出oid了 string strMarcSyntaxOID = GetMarcSyntaxOID(instance, strDbName); RetrivalRecord record = new RetrivalRecord { m_strDatabaseName = strDbName }; // 根据书目库名获得书目库属性对象 BiblioDbProperty prop = instance.zhost.GetDbProperty( strDbName, false); int nRet = GetIso2709Record(dp2library_record, e.Request.m_elementSetNames, prop != null ? prop.AddField901 : false, prop != null ? prop.RemoveFields : "997", zserver_channel.SetProperty().MarcRecordEncoding, out byte[] baIso2709, out strError); /* * // 测试记录群中包含诊断记录 * if (i == 1) * { * nRet = -1; * strError = "测试获取记录错误"; * } */ if (nRet == -1) { record.m_surrogateDiagnostic = new DiagFormat { m_strDiagSetID = "1.2.840.10003.4.1", m_nDiagCondition = 14, // system error in presenting records m_strAddInfo = strError }; } else if (nRet == 0) { record.m_surrogateDiagnostic = new DiagFormat { m_strDiagSetID = "1.2.840.10003.4.1", m_nDiagCondition = 1028, // record deleted m_strAddInfo = strError }; } else if (String.IsNullOrEmpty(strMarcSyntaxOID) == true) { // 根据数据库名无法获得marc syntax oid。可能是虚拟库检索命中记录所在的物理库没有在 capo.xml 中配置。 record.m_surrogateDiagnostic = new DiagFormat { m_strDiagSetID = "1.2.840.10003.4.1", m_nDiagCondition = 109, // database unavailable // 似乎235:database dos not exist也可以 m_strAddInfo = "根据数据库名 '" + strDbName + "' 无法获得 marc syntax oid" }; } else { record.m_external = new External { m_strDirectRefenerce = strMarcSyntaxOID, m_octectAligned = baIso2709 }; } nSize += record.GetPackageSize(); if (i == 0) { // 连一条记录也放不下 if (nSize > zserver_channel.SetProperty().ExceptionalRecordSize) { Debug.Assert(diag == null, ""); ZProcessor.SetPresentDiagRecord(ref diag, 17, // record exceeds Exceptional_record_size "记录尺寸 " + nSize.ToString() + " 超过 Exceptional_record_size " + zserver_channel.SetProperty().ExceptionalRecordSize.ToString()); lNumber = 0; break; } } else { if (nSize >= zserver_channel.SetProperty().PreferredMessageSize) { // 调整返回的记录数 lNumber = i; break; } } records.Add(record); } i++; } } catch (Exception ex) { strError = "获取结果集时出现异常: " + ex.Message; goto ERROR1; } finally { instance.MessageConnection.ReturnChannel(library_channel); } e.Records = records; e.Diag = diag; return; ERROR1: { DiagFormat diag1 = null; ZProcessor.SetPresentDiagRecord(ref diag1, 2, // temporary system error strError); e.Diag = diag1; // e.Result = new ZClient.SearchResult { Value = -1, ErrorInfo = strError }; return; } }