Example #1
0
        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;
            }
        }
Example #2
0
        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;
            }
        }