// 解码Present请求包 public static int Decode_PresentRequest( BerNode root, out PresentRequestInfo info, out string strError) { strError = ""; int nRet = 0; info = new PresentRequestInfo(); Debug.Assert(root != null, ""); if (root.m_uTag != BerTree.z3950_presentRequest) { strError = "root tag is not z3950_presentRequest"; return -1; } for (int i = 0; i < root.ChildrenCollection.Count; i++) { BerNode node = root.ChildrenCollection[i]; switch (node.m_uTag) { case BerTree.z3950_ReferenceId: // 2 info.m_strReferenceId = node.GetCharNodeData(); break; case BerTree.z3950_ResultSetId: // 31 resultSetId (IntenationalString) info.m_strResultSetID = node.GetCharNodeData(); break; case BerTree.z3950_resultSetStartPoint: // 30 resultSetStartPoint (Integer) info.m_lResultSetStartPoint = node.GetIntegerNodeData(); break; case BerTree.z3950_numberOfRecordsRequested: // 29 numberOfRecordsRequested (Integer) info.m_lNumberOfRecordsRequested = node.GetIntegerNodeData(); break; case BerTree.z3950_ElementSetNames: // 19 ElementSetNames (complicates) { List<string> elementset_names = null; nRet = DecodeElementSetNames(node, out elementset_names, out strError); if (nRet == -1) return -1; info.m_elementSetNames = elementset_names; } break; default: break; } } return 0; }
// 编码(构造) Present响应包 int Encode_PresentResponse(PresentRequestInfo info, out byte[] baPackage) { baPackage = null; int nRet = 0; string strError = ""; DiagFormat diag = null; BerTree tree = new BerTree(); BerNode root = null; string strResultSetName = info.m_strResultSetID; if (String.IsNullOrEmpty(strResultSetName) == true) strResultSetName = "default"; long lStart = info.m_lResultSetStartPoint - 1; long lNumber = info.m_lNumberOfRecordsRequested; long lPerCount = lNumber; long lHitCount = 0; List<string> paths = new List<string>(); int nPresentStatus = 5; // failed // 获取结果集中需要部分的记录path long lOffset = lStart; int nCount = 0; for (; ; ) { DigitalPlatform.LibraryClient.localhost.Record[] searchresults = null; long lRet = this._channel.GetSearchResult( null, // stop, strResultSetName, // strResultSetName lOffset, lPerCount, "id", "zh", // this.Lang, out searchresults, out strError); /* // 测试获取结果集失败的情况,返回非代理诊断记录 lRet = -1; strError = "测试检索错误信息!"; * */ if (lRet == -1) { SetPresentDiagRecord(ref diag, 2, // temporary system error strError); break; } if (lRet == 0) { // goto ERROR1 ? } lHitCount = lRet; // 顺便得到命中记录总条数 // 转储 for (int i = 0; i < searchresults.Length; i++) { paths.Add(searchresults[i].Path); } lOffset += searchresults.Length; lPerCount -= searchresults.Length; nCount += searchresults.Length; if (lOffset >= lHitCount || lPerCount <= 0 || nCount >= lNumber) { // break; } } // TODO: 需要注意多个错误是否形成多个diag记录?V2不允许这样,V3允许这样 if (lHitCount < info.m_lResultSetStartPoint && diag == null) { strError = "start参数值 " + info.m_lResultSetStartPoint + " 超过结果集中记录总数 " + lHitCount; // return -1; // 如果表示错误状态? SetPresentDiagRecord(ref diag, 13, // Present request out-of-range strError); } int MAX_PRESENT_RECORD = 100; // 限制每次 present 的记录数量 if (lNumber > MAX_PRESENT_RECORD) lNumber = MAX_PRESENT_RECORD; long nNextResultSetPosition = 0; // if (lHitCount < (lStart - 1) + lNumber) { // 是 present 错误,但还可以调整 lNumber lNumber = lHitCount - (lStart - 1); nNextResultSetPosition = 0; } else { // nNextResultSetPosition = lStart + lNumber + 1; } root = tree.m_RootNode.NewChildConstructedNode( BerTree.z3950_presentResponse, BerNode.ASN1_CONTEXT); // reference id if (String.IsNullOrEmpty(info.m_strReferenceId) == false) { root.NewChildCharNode(BerTree.z3950_ReferenceId, BerNode.ASN1_CONTEXT, Encoding.UTF8.GetBytes(info.m_strReferenceId)); } List<RetrivalRecord> records = new List<RetrivalRecord>(); // 获取要返回的MARC记录 if (diag == null) { // 记录编码格式为 GRS-1 (generic-record-syntax-1) : // EXTERNAL // --- OID (Object Identifier) // --- MARC (OCTET STRING) // m_strOID = _T("1.2.840.10003.5.1"); // OID of UNIMARC // m_strOID = _T("1.2.840.10003.5.10"); // OID of USMARC // // 需要建立一个数据库名和oid的对照表,方面快速取得数据库MARC syntax OID // TODO: 编码过程中,可能会发现记录太多,总尺寸超过Initial中规定的prefered message size。 // 这样需要减少返回的记录数量。这样,就需要先做这里的循环,后构造另外几个参数 int nSize = 0; for (int i = 0; i < (int)lNumber; i++) { // 编码 N 条 MARC 记录 // // if (m_bStop) return false; // 取出数据库指针 // lStart 不是 0 起点的 string strPath = paths[i]; // 解析出数据库名和ID string strDbName = Global.GetDbName(strPath); string strRecID = Global.GetRecordID(strPath); // 如果取得的是xml记录,则根元素可以看出记录的marc syntax,进一步可以获得oid; // 如果取得的是MARC格式记录,则需要根据数据库预定义的marc syntax来看出oid了 string strMarcSyntaxOID = GetMarcSyntaxOID(strDbName); byte[] baMARC = null; RetrivalRecord record = new RetrivalRecord(); record.m_strDatabaseName = strDbName; // 根据书目库名获得书目库属性对象 BiblioDbProperty prop = this._service.GetDbProperty( strDbName, false); nRet = GetMARC(strPath, info.m_elementSetNames, prop != null ? prop.AddField901 : false, out baMARC, out strError); /* // 测试记录群中包含诊断记录 if (i == 1) { nRet = -1; strError = "测试获取记录错误"; }*/ if (nRet == -1) { record.m_surrogateDiagnostic = new DiagFormat(); record.m_surrogateDiagnostic.m_strDiagSetID = "1.2.840.10003.4.1"; record.m_surrogateDiagnostic.m_nDiagCondition = 14; // system error in presenting records record.m_surrogateDiagnostic.m_strAddInfo = strError; } else if (nRet == 0) { record.m_surrogateDiagnostic = new DiagFormat(); record.m_surrogateDiagnostic.m_strDiagSetID = "1.2.840.10003.4.1"; record.m_surrogateDiagnostic.m_nDiagCondition = 1028; // record deleted record.m_surrogateDiagnostic.m_strAddInfo = strError; } else if (String.IsNullOrEmpty(strMarcSyntaxOID) == true) { // 根据数据库名无法获得marc syntax oid。可能是虚拟库检索命中记录所在的物理库没有在dp2zserver.xml中配置。 record.m_surrogateDiagnostic = new DiagFormat(); record.m_surrogateDiagnostic.m_strDiagSetID = "1.2.840.10003.4.1"; record.m_surrogateDiagnostic.m_nDiagCondition = 109; // database unavailable // 似乎235:database dos not exist也可以 record.m_surrogateDiagnostic.m_strAddInfo = "根据数据库名 '" + strDbName + "' 无法获得marc syntax oid"; } else { record.m_external = new External(); record.m_external.m_strDirectRefenerce = strMarcSyntaxOID; record.m_external.m_octectAligned = baMARC; } nSize += record.GetPackageSize(); if (i == 0) { // 连一条记录也放不下 if (nSize > this._lExceptionalRecordSize) { Debug.Assert(diag == null, ""); SetPresentDiagRecord(ref diag, 17, // record exceeds Exceptional_record_size "记录尺寸 " + nSize.ToString() + " 超过 Exceptional_record_size " + this._lExceptionalRecordSize.ToString()); lNumber = 0; break; } } else { if (nSize >= this._lPreferredMessageSize) { // 调整返回的记录数 lNumber = i; break; } } records.Add(record); } } // numberOfRecordsReturned root.NewChildIntegerNode(BerTree.z3950_NumberOfRecordsReturned, // 24 BerNode.ASN1_CONTEXT, // ASN1_PRIMITIVE BUG!!! BitConverter.GetBytes((long)lNumber)); if (diag != null) nPresentStatus = 5; else nPresentStatus = 0; // nextResultSetPosition // if 0, that's end of the result set // else M+1, M is 最后一次 present response 的最后一条记录在 result set 中的 position root.NewChildIntegerNode(BerTree.z3950_NextResultSetPosition, // 25 BerNode.ASN1_CONTEXT, // ASN1_PRIMITIVE BUG!!! BitConverter.GetBytes((long)nNextResultSetPosition)); // presentStatus // success (0), // partial-1 (1), // partial-2 (2), // partial-3 (3), // partial-4 (4), // failure (5). root.NewChildIntegerNode(BerTree.z3950_presentStatus, // 27 BerNode.ASN1_CONTEXT, // ASN1_PRIMITIVE BUG!!! BitConverter.GetBytes((long)nPresentStatus)); // 诊断记录 if (diag != null) { BerNode nodeDiagRoot = root.NewChildConstructedNode(BerTree.z3950_nonSurrogateDiagnostic, // 130 BerNode.ASN1_CONTEXT); diag.BuildBer(nodeDiagRoot); /* nodeDiagRoot.NewChildOIDsNode(6, BerNode.ASN1_UNIVERSAL, diag.m_strDiagSetID); // "1.2.840.10003.4.1" nodeDiagRoot.NewChildIntegerNode(2, BerNode.ASN1_UNIVERSAL, BitConverter.GetBytes((long)diag.m_nDiagCondition)); if (String.IsNullOrEmpty(diag.m_strAddInfo) == false) { nodeDiagRoot.NewChildCharNode(26, BerNode.ASN1_UNIVERSAL, Encoding.UTF8.GetBytes(diag.m_strAddInfo)); } * */ } // 如果 present 是非法的,到这里打包完成,可以返回了 if (0 != nPresentStatus) goto END1; // 编码记录BER树 // 以下为 present 成功时,打包返回记录。 // present success // presRoot records child, constructed (choice of ... ... optional) // if present fail, then may be no records 'node' // Records ::= CHOICE { // responseRecords [28] IMPLICIT SEQUENCE OF NamePlusRecord, // nonSurrogateDiagnostic [130] IMPLICIT DefaultDiagFormat, // multipleNonSurDiagnostics [205] IMPLICIT SEQUENCE OF DiagRec} // 当 present 成功时,response 选择了 NamePlusRecord (数据库名 + 记录) BerNode node = root.NewChildConstructedNode(BerTree.z3950_dataBaseOrSurDiagnostics, // 28 BerNode.ASN1_CONTEXT); for (int i = 0; i < records.Count; i++) { RetrivalRecord record = records[i]; record.BuildNamePlusRecord(node); } END1: baPackage = null; root.EncodeBERPackage(ref baPackage); return 0; }