Example #1
0
        // 从 dp2library 服务器获得全部 isbn 和 title 字符串
        IsbnResult GetIsbnStrings()
        {
            LibraryChannel channel = _channelPool.GetChannel(this.textBox_dp2libraryUrl.Text, "public");

            try
            {
                // TODO: <全部UNIMARC>
                long lRet = channel.SearchBiblio("<全部>", "", -1, "isbn",
                                                 "left", "zh", "default", "", "", "",
                                                 out string strQueryXml, out string strError);
                if (lRet == -1)
                {
                    return new IsbnResult {
                               Value = -1, ErrorInfo = strError
                    }
                }
                ;
                ResultSetLoader loader = new ResultSetLoader(channel, "default",
                                                             "id,xml");
                IsbnResult result = new IsbnResult();
                result.IsbnList = new List <string>();
                foreach (Record record in loader)
                {
                    // XML 转换为 MARC
                    int nRet = MarcUtil.Xml2Marc(record.RecordBody.Xml,
                                                 false,
                                                 "",
                                                 out string strMarcSyntax,
                                                 out string strMARC,
                                                 out strError);

                    if (nRet != 0)
                    {
                        continue;
                    }

                    // 从 MARC 中取 010$a
                    var    marc_record = new MarcRecord(strMARC);
                    string xpath       = "field[@name='010']/subfield[@name='a']";
                    if (strMarcSyntax == "usmarc")
                    {
                        xpath = "field[@name='020']/subfield[@name='a']";
                    }
                    var nodes = marc_record.select(xpath);

                    foreach (MarcSubfield subfield in nodes)
                    {
                        result.IsbnList.Add(subfield.Content);
                    }
                }

                return(result);
            }
            finally
            {
                _channelPool.ReturnChannel(channel);
            }
        }
Example #2
0
        // 初始化时列出当前馆藏地应有的全部图书
        // 本函数中,只给 Entity 对象里面设置好了 PII,其他成员尚未设置
        static void FillLocationBooks(EntityCollection entities,
                                      string location,
                                      CancellationToken token)
        {
            var channel = App.CurrentApp.GetChannel();

            try
            {
                long lRet = channel.SearchItem(null,
                                               "<全部>",
                                               location,
                                               5000,
                                               "馆藏地点",
                                               "exact",
                                               "zh",
                                               "shelfResultset",
                                               "",
                                               "",
                                               out string strError);
                if (lRet == -1)
                {
                    throw new ChannelException(channel.ErrorCode, strError);
                }

                string strStyle = "id,cols,format:@coldef:*/barcode|*/borrower";

                ResultSetLoader loader = new ResultSetLoader(channel,
                                                             null,
                                                             "shelfResultset",
                                                             strStyle,
                                                             "zh");
                foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader)
                {
                    token.ThrowIfCancellationRequested();
                    string pii = record.Cols[0];
                    Application.Current.Dispatcher.Invoke(new Action(() =>
                    {
                        entities.Add(pii);
                    }));
                }
            }
            finally
            {
                App.CurrentApp.ReturnChannel(channel);
            }
        }
Example #3
0
        // 第一阶段:获得全部读者库记录,进入本地数据库
        // result.Value
        //      -1  出错
        //      >=0 实际获得的读者记录条数
        public static async Task <ReplicationPlan> DownloadAllPatronRecordAsync(CancellationToken token)
        {
            LibraryChannel channel     = App.CurrentApp.GetChannel();
            var            old_timeout = channel.Timeout;

            channel.Timeout = TimeSpan.FromMinutes(5);  // 设置 5 分钟。因为读者记录检索需要一定时间
            try
            {
                ReplicationPlan plan = GetReplicationPlan(channel);
                if (plan.Value == -1)
                {
                    return(plan);
                }


                int nRedoCount = 0;
REDO:
                if (token.IsCancellationRequested)
                {
                    return new ReplicationPlan
                           {
                               Value     = -1,
                               ErrorInfo = "用户中断"
                           }
                }
                ;
                // 检索全部读者库记录
                long lRet = channel.SearchReader(null,  // stop,
                                                 "<all>",
                                                 "",
                                                 -1,
                                                 "__id",
                                                 "left",
                                                 "zh",
                                                 null, // strResultSetName
                                                 "",   // strOutputStyle
                                                 out string strError);
                if (lRet == -1)
                {
                    // 一次重试机会
                    if (lRet == -1 &&
                        (channel.ErrorCode == ErrorCode.RequestCanceled || channel.ErrorCode == ErrorCode.RequestError) &&
                        nRedoCount < 2)
                    {
                        nRedoCount++;
                        goto REDO;
                    }

                    return(new ReplicationPlan
                    {
                        Value = -1,
                        ErrorInfo = strError,
                        ErrorCode = channel.ErrorCode.ToString()
                    });
                }

                long hitcount = lRet;

                // 把超时时间改短一点
                channel.Timeout = TimeSpan.FromSeconds(20);

                DateTime search_time = DateTime.Now;

                // 获取和存储记录
                ResultSetLoader loader = new ResultSetLoader(channel,
                                                             null,
                                                             null,
                                                             $"id,xml,timestamp",
                                                             "zh");
                using (BiblioCacheContext context = new BiblioCacheContext())
                {
                    context.Database.EnsureCreated();

                    // 删除 Patrons 里面的已有记录
                    context.Patrons.RemoveRange(context.Patrons.ToList());
                    await context.SaveChangesAsync(token);

                    // loader.Prompt += this.Loader_Prompt;
                    if (hitcount > 0)
                    {
                        int i = 0;
                        foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader)
                        {
                            if (token.IsCancellationRequested)
                            {
                                return new ReplicationPlan
                                       {
                                           Value     = -1,
                                           ErrorInfo = "用户中断"
                                       }
                            }
                            ;

                            PatronItem item = new PatronItem();

                            var result = Set(item, record, search_time);
                            if (result.Value == -1)
                            {
                                // TODO: 是否汇总报错信息?
                                continue;
                            }
                            context.Patrons.Add(item);

                            if ((i % 10) == 0)
                            {
                                await context.SaveChangesAsync(token);
                            }

                            i++;
                        }

                        await context.SaveChangesAsync(token);
                    }
                }

                return(new ReplicationPlan
                {
                    Value = (int)hitcount,
                    StartDate = plan.StartDate
                });
            }
            catch (Exception ex)
            {
                return(new ReplicationPlan
                {
                    Value = -1,
                    ErrorInfo = $"DownloadAllPatronRecord() 出现异常:{ex.Message}"
                });
            }
            finally
            {
                channel.Timeout = old_timeout;
                App.CurrentApp.ReturnChannel(channel);
            }
        }
Example #4
0
        // 初始化一个读者库的指纹缓存
        // return:
        //      -1  出错
        //      >=0 实际发送给接口程序的事项数目
        static int BuildOneDbCache(
            LibraryChannel channel,
            string strDir,
            string strReaderDbName,
            CancellationToken token,
            out string strError)
        {
            strError = "";
            int nRet = 0;

            DpResultSet resultset = null;
            bool        bCreate   = false;

            Hashtable timestamp_table = new Hashtable();    // recpath --> fingerprint timestamp

            ShowMessage(strReaderDbName);

            // 结果集文件名
            string strResultsetFilename = Path.Combine(strDir, strReaderDbName);

            if (File.Exists(strResultsetFilename) == false)
            {
                resultset = new DpResultSet(false, false);
                resultset.Create(strResultsetFilename,
                                 strResultsetFilename + ".index");
                bCreate = true;
            }
            else
            {
                bCreate = false;
            }

            // *** 第一阶段, 创建新的结果集文件;或者获取全部读者记录中的指纹时间戳

            bool bDone = false;    // 创建情形下 是否完成了写入操作

            try
            {
                /*
                 * long lRet = Channel.SearchReader(stop,
                 * strReaderDbName,
                 * "1-9999999999",
                 * -1,
                 * "__id",
                 * "left",
                 * this.Lang,
                 * null,   // strResultSetName
                 * "", // strOutputStyle
                 * out strError);
                 */
                long lRet = channel.SearchReader(null,  // stop,
                                                 strReaderDbName,
                                                 "",
                                                 -1,
                                                 "指纹时间戳",
                                                 "left",
                                                 ClientInfo.Lang,
                                                 null, // strResultSetName
                                                 "",   // strOutputStyle
                                                 out strError);
                if (lRet == -1)
                {
                    if (channel.ErrorCode == ErrorCode.AccessDenied)
                    {
                        strError = "用户 " + channel.UserName + " 权限不足: " + strError;
                    }
                    return(-1);
                }

                if (lRet == 0)
                {
                    // TODO: 这时候如果以前有结果集文件还会残留,但不会影响功能正确性,可以改进为把残留的结果集文件删除
                    return(0);
                }

                long lHitCount = lRet;

                ResultSetLoader loader = new ResultSetLoader(channel,
                                                             null,
                                                             null,
                                                             bCreate == true ? "id,cols,format:cfgs/browse_fingerprint" : "id,cols,format:cfgs/browse_fingerprinttimestamp",
                                                             ClientInfo.Lang);
                loader.Prompt += Loader_Prompt;

                foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader)
                {
                    token.ThrowIfCancellationRequested();

                    ShowMessage("正在处理读者记录 " + record.Path);

                    if (bCreate == true)
                    {
                        if (record.Cols == null || record.Cols.Length < 3)
                        {
                            strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint";
                            return(-1);
                        }
                        if (string.IsNullOrEmpty(record.Cols[0]) == true)
                        {
                            continue;   // 读者记录中没有指纹信息
                        }
                        DpRecord item = new DpRecord(record.Path);
                        // timestamp | barcode | fingerprint
                        item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2];
                        resultset.Add(item);
                    }
                    else
                    {
                        if (record.Cols == null || record.Cols.Length < 1)
                        {
                            strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprinttimestamp";
                            return(-1);
                        }
                        if (record.Cols.Length < 2)
                        {
                            strError = "record.Cols error ... 需要刷新配置文件 cfgs/browse_fingerprinttimestamp 到最新版本";
                            return(-1);
                        }
                        if (string.IsNullOrEmpty(record.Cols[0]) == true)
                        {
                            continue;   // 读者记录中没有指纹信息
                        }
                        // 记载时间戳
                        // timestamp | barcode
                        timestamp_table[record.Path] = record.Cols[0] + "|" + record.Cols[1];
                    }
                }

#if NO
                // stop.SetProgressRange(0, lHitCount);

                long lStart = 0;
                long lCount = lHitCount;
                DigitalPlatform.LibraryClient.localhost.Record[] searchresults = null;

                // 装入浏览格式
                for (; ;)
                {
                    token.ThrowIfCancellationRequested();


                    lRet = channel.GetSearchResult(
                        null,
                        null,   // strResultSetName
                        lStart,
                        lCount,
                        bCreate == true ? "id,cols,format:cfgs/browse_fingerprint" : "id,cols,format:cfgs/browse_fingerprinttimestamp",
                        ClientInfo.Lang,
                        out searchresults,
                        out strError);
                    if (lRet == -1)
                    {
                        return(-1);
                    }

                    if (lRet == 0)
                    {
                        strError = "GetSearchResult() return 0";
                        return(-1);
                    }

                    Debug.Assert(searchresults != null, "");
                    Debug.Assert(searchresults.Length > 0, "");

                    for (int i = 0; i < searchresults.Length; i++)
                    {
                        DigitalPlatform.LibraryClient.localhost.Record record = searchresults[i];
                        if (bCreate == true)
                        {
                            if (record.Cols == null || record.Cols.Length < 3)
                            {
                                strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint";
                                return(-1);
                            }
                            if (string.IsNullOrEmpty(record.Cols[0]) == true)
                            {
                                continue;   // 读者记录中没有指纹信息
                            }
                            DpRecord item = new DpRecord(record.Path);
                            // timestamp | barcode | fingerprint
                            item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2];
                            resultset.Add(item);
                        }
                        else
                        {
                            if (record.Cols == null || record.Cols.Length < 1)
                            {
                                strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprinttimestamp";
                                return(-1);
                            }
                            if (record.Cols.Length < 2)
                            {
                                strError = "record.Cols error ... 需要刷新配置文件 cfgs/browse_fingerprinttimestamp 到最新版本";
                                return(-1);
                            }
                            if (string.IsNullOrEmpty(record.Cols[0]) == true)
                            {
                                continue;   // 读者记录中没有指纹信息
                            }
                            // 记载时间戳
                            // timestamp | barcode
                            timestamp_table[record.Path] = record.Cols[0] + "|" + record.Cols[1];
                        }
                    }

                    lStart += searchresults.Length;
                    lCount -= searchresults.Length;

                    //stop.SetMessage(strReaderDbName + " 包含记录 " + lHitCount.ToString() + " 条,已装入 " + lStart.ToString() + " 条");

                    if (lStart >= lHitCount || lCount <= 0)
                    {
                        break;
                    }
                    //stop.SetProgressValue(lStart);
                }
#endif

                if (bCreate == true)
                {
                    bDone = true;
                }

                if (bCreate == true)
                {
                    // return:
                    //      -2  remoting服务器连接失败。驱动程序尚未启动
                    //      -1  出错
                    //      >=0 实际发送给接口程序的事项数目
                    nRet = CreateFingerprintCache(resultset,
                                                  out strError);
                    if (nRet == -1 || nRet == -2)
                    {
                        return(-1);
                    }

                    return(nRet);
                }
            }
            finally
            {
                if (bCreate == true)
                {
                    Debug.Assert(resultset != null, "");
                    if (bDone == true)
                    {
                        resultset.Detach(out string strTemp1,
                                         out string strTemp2);
                    }
                    else
                    {
                        // 否则文件会被删除
                        resultset.Close();
                    }
                }
            }

            // 比对时间戳,更新结果集文件
            Hashtable update_table = new Hashtable();   // 需要更新的事项。recpath --> 1
            resultset = new DpResultSet(false, false);
            resultset.Attach(strResultsetFilename,
                             strResultsetFilename + ".index");
            try
            {
                long nCount = resultset.Count;
                for (long i = 0; i < nCount; i++)
                {
                    token.ThrowIfCancellationRequested();


                    DpRecord record = resultset[i];

                    string strRecPath = record.ID;

                    ShowMessage("比对 " + strRecPath);

                    // timestamp | barcode
                    string strNewTimestamp = (string)timestamp_table[strRecPath];
                    if (strNewTimestamp == null)
                    {
                        // 最新状态下,读者记录已经不存在,需要从结果集中删除
                        resultset.RemoveAt((int)i);
                        i--;
                        nCount--;
                        continue;
                    }

                    // 拆分出证条码号 2013/1/28
                    string strNewBarcode = "";
                    nRet = strNewTimestamp.IndexOf("|");
                    if (nRet != -1)
                    {
                        strNewBarcode   = strNewTimestamp.Substring(nRet + 1);
                        strNewTimestamp = strNewTimestamp.Substring(0, nRet);
                    }

                    // 最新读者记录中已经没有指纹信息。例如读者记录中的指纹元素被删除了
                    if (string.IsNullOrEmpty(strNewTimestamp) == true)
                    {
                        // 删除现有事项
                        resultset.RemoveAt((int)i);
                        i--;
                        nCount--;

                        timestamp_table.Remove(strRecPath);
                        continue;
                    }

                    // 取得结果集文件中的原有时间戳字符串
                    string strText = record.BrowseText; // timestamp | barcode | fingerprint
                    nRet = strText.IndexOf("|");
                    if (nRet == -1)
                    {
                        strError = "browsetext 错误,没有 '|' 字符";
                        return(-1);
                    }
                    string strOldTimestamp = strText.Substring(0, nRet);
                    // timestamp | barcode | fingerprint
                    string strOldBarcode = strText.Substring(nRet + 1);
                    nRet = strOldBarcode.IndexOf("|");
                    if (nRet != -1)
                    {
                        strOldBarcode = strOldBarcode.Substring(0, nRet);
                    }

                    // 时间戳发生变化,需要更新事项
                    if (strNewTimestamp != strOldTimestamp ||
                        strNewBarcode != strOldBarcode)
                    {
                        // 如果证条码号为空,无法建立对照关系,要跳过
                        if (string.IsNullOrEmpty(strNewBarcode) == false)
                        {
                            update_table[strRecPath] = 1;
                        }

                        // 删除现有事项
                        resultset.RemoveAt((int)i);
                        i--;
                        nCount--;
                    }
                    timestamp_table.Remove(strRecPath);
                }

                // 循环结束后,timestamp_table中剩余的是当前结果集文件中没有包含的那些读者记录路径

                if (update_table.Count > 0)
                {
                    // 获取指纹信息,追加到结果集文件的尾部
                    // parameters:
                    //      update_table   key为读者记录路径
                    AppendFingerprintInfo(
                        channel,
                        resultset,
                        update_table,
                        token);
                }

                // 如果服务器端新增了指纹信息,需要获取后追加到结果集文件尾部
                if (timestamp_table.Count > 0)
                {
                    // 获取指纹信息,追加到结果集文件的尾部
                    // parameters:
                    //      update_table   key为读者记录路径
                    AppendFingerprintInfo(
                        channel,
                        resultset,
                        timestamp_table,
                        token);
                }

                // return:
                //      -2  remoting服务器连接失败。驱动程序尚未启动
                //      -1  出错
                //      >=0 实际发送给接口程序的事项数目
                nRet = CreateFingerprintCache(resultset,
                                              out strError);
                if (nRet == -1 || nRet == -2)
                {
                    return(-1);
                }

                return(nRet);
            }
            finally
            {
                resultset.Detach(out string strTemp1, out string strTemp2);
            }
        }
Example #5
0
        // 第一阶段:获得全部读者库记录,进入本地数据库
        // result.Value
        //      -1  出错
        //      >=0 实际获得的读者记录条数
        public static async Task <ReplicationPlan> DownloadAllPatronRecordAsync(
            Delegate_writeLog writeLog,
            CancellationToken token)
        {
            _inDownloadingPatron++;

            // 2020/9/26
            if (_inDownloadingPatron > 1)
            {
                _inDownloadingPatron--;
                return(new ReplicationPlan
                {
                    Value = -1,
                    ErrorCode = "running",
                    ErrorInfo = "前一次的“下载全部读者记录到本地缓存”过程还在进行中,本次触发被放弃"
                });
            }

            writeLog?.Invoke($"开始下载全部读者记录到本地缓存");
            LibraryChannel channel     = App.CurrentApp.GetChannel();
            var            old_timeout = channel.Timeout;

            channel.Timeout = TimeSpan.FromMinutes(5);  // 设置 5 分钟。因为读者记录检索需要一定时间
            try
            {
                ReplicationPlan plan = GetReplicationPlan(channel);

                writeLog?.Invoke($"GetReplicationPlan() return {plan.ToString()}");

                if (plan.Value == -1)
                {
                    return(plan);
                }

                int nRedoCount = 0;
REDO:
                if (token.IsCancellationRequested)
                {
                    return new ReplicationPlan
                           {
                               Value     = -1,
                               ErrorInfo = "用户中断"
                           }
                }
                ;
                // 检索全部读者库记录
                long lRet = channel.SearchReader(null,  // stop,
                                                 "<all>",
                                                 "",
                                                 -1,
                                                 "__id",
                                                 "left",
                                                 "zh",
                                                 null, // strResultSetName
                                                 "",   // strOutputStyle
                                                 out string strError);
                if (lRet == -1)
                {
                    writeLog?.Invoke($"SearchReader() 出错, strError={strError}, channel.ErrorCode={channel.ErrorCode}");

                    // 一次重试机会
                    if (lRet == -1 &&
                        (channel.ErrorCode == ErrorCode.RequestCanceled || channel.ErrorCode == ErrorCode.RequestError) &&
                        nRedoCount < 2)
                    {
                        nRedoCount++;
                        goto REDO;
                    }

                    return(new ReplicationPlan
                    {
                        Value = -1,
                        ErrorInfo = strError,
                        ErrorCode = channel.ErrorCode.ToString()
                    });
                }

                long hitcount = lRet;

                writeLog?.Invoke($"共检索命中读者记录 {hitcount} 条");

                // 把超时时间改短一点
                channel.Timeout = TimeSpan.FromSeconds(20);

                DateTime search_time = DateTime.Now;

                Hashtable pii_table   = new Hashtable();
                int       skip_count  = 0;
                int       error_count = 0;

                // 获取和存储记录
                ResultSetLoader loader = new ResultSetLoader(channel,
                                                             null,
                                                             null,
                                                             $"id,xml,timestamp",
                                                             "zh");
                using (BiblioCacheContext context = new BiblioCacheContext())
                {
                    context.Database.EnsureCreated();

                    // 删除 Patrons 里面的已有记录
                    context.Patrons.RemoveRange(context.Patrons.ToList());
                    await context.SaveChangesAsync(token);

                    // loader.Prompt += this.Loader_Prompt;
                    if (hitcount > 0)
                    {
                        int i = 0;
                        foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader)
                        {
                            if (token.IsCancellationRequested)
                            {
                                return new ReplicationPlan
                                       {
                                           Value     = -1,
                                           ErrorInfo = "用户中断"
                                       }
                            }
                            ;

                            PatronItem item = new PatronItem();

                            // result.Value:
                            //      -1  出错
                            //      0   需要跳过这条读者记录
                            //      1   成功
                            var result = Set(item, record, search_time);
                            if (result.Value == -1 || result.Value == 0)
                            {
                                // TODO: 是否汇总报错信息?

                                if (result.Value == -1)
                                {
                                    writeLog?.Invoke($"Set() ({item.RecPath}) 出错: {result.ErrorInfo}");
                                    error_count++;
                                }
                                if (result.Value == 0)
                                {
                                    skip_count++;
                                }
                                continue;
                            }

                            //
                            if (pii_table.ContainsKey(result.PII))
                            {
                                string recpath = (string)pii_table[result.PII];
                                writeLog?.Invoke($"发现读者记录 {item.RecPath} 的 PII '{result.PII}' 和 {recpath} 的 PII 重复了。跳过它");
                                continue;
                            }

                            pii_table[result.PII] = item.RecPath;

                            // TODO: PII 应该是包含 OI 的严格形态
                            context.Patrons.Add(item);

                            if ((i % 10) == 0)
                            {
                                await context.SaveChangesAsync(token);
                            }

                            i++;
                        }

                        await context.SaveChangesAsync(token);
                    }
                }

                writeLog?.Invoke($"plan.StartDate='{plan.StartDate}'。skip_count={skip_count}, error_count={error_count}。返回");

                return(new ReplicationPlan
                {
                    Value = (int)hitcount,
                    StartDate = plan.StartDate
                });
            }
            catch (Exception ex)
            {
                // 2020/9/26
                writeLog?.Invoke($"DownloadAllPatronRecord() 出现异常:{ExceptionUtil.GetDebugText(ex)}");

                return(new ReplicationPlan
                {
                    Value = -1,
                    ErrorInfo = $"DownloadAllPatronRecord() 出现异常:{ex.Message}"
                });
            }
            finally
            {
                channel.Timeout = old_timeout;
                App.CurrentApp.ReturnChannel(channel);

                writeLog?.Invoke($"结束下载全部读者记录到本地缓存");

                _inDownloadingPatron--;
            }
        }
Example #6
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 #7
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;
            }
        }
Example #8
0
        // parameters:
        //      uid_table   返回 UID --> PII 对照表
        public static NormalResult DownloadUidTable(
            List <string> item_dbnames,
            Hashtable uid_table,
            delegate_showText func_showProgress,
            // Delegate_writeLog writeLog,
            CancellationToken token)
        {
            WpfClientInfo.WriteInfoLog($"开始下载全部册记录到本地缓存");
            LibraryChannel channel     = App.CurrentApp.GetChannel();
            var            old_timeout = channel.Timeout;

            channel.Timeout = TimeSpan.FromMinutes(5);  // 设置 5 分钟。因为册记录检索需要一定时间
            try
            {
                if (item_dbnames == null)
                {
                    long lRet = channel.GetSystemParameter(
                        null,
                        "item",
                        "dbnames",
                        out string strValue,
                        out string strError);
                    if (lRet == -1)
                    {
                        return new NormalResult
                               {
                                   Value     = -1,
                                   ErrorInfo = strError,
                                   ErrorCode = channel.ErrorCode.ToString()
                               }
                    }
                    ;
                    item_dbnames = StringUtil.SplitList(strValue);
                    StringUtil.RemoveBlank(ref item_dbnames);
                }

                foreach (string dbName in item_dbnames)
                {
                    func_showProgress?.Invoke($"正在从 {dbName} 获取信息 ...");

                    int nRedoCount = 0;
REDO:
                    if (token.IsCancellationRequested)
                    {
                        return new NormalResult
                               {
                                   Value     = -1,
                                   ErrorInfo = "用户中断"
                               }
                    }
                    ;
                    // 检索全部读者库记录
                    long lRet = channel.SearchItem(null,
                                                   dbName, // "<all>",
                                                   "",
                                                   -1,
                                                   "__id",
                                                   "left",
                                                   "zh",
                                                   null, // strResultSetName
                                                   "",   // strSearchStyle
                                                   "",   // strOutputStyle
                                                   out string strError);
                    if (lRet == -1)
                    {
                        WpfClientInfo.WriteErrorLog($"SearchItem() 出错, strError={strError}, channel.ErrorCode={channel.ErrorCode}");

                        // 一次重试机会
                        if (lRet == -1 &&
                            (channel.ErrorCode == ErrorCode.RequestCanceled || channel.ErrorCode == ErrorCode.RequestError) &&
                            nRedoCount < 2)
                        {
                            nRedoCount++;
                            goto REDO;
                        }

                        return(new NormalResult
                        {
                            Value = -1,
                            ErrorInfo = strError,
                            ErrorCode = channel.ErrorCode.ToString()
                        });
                    }

                    long hitcount = lRet;

                    WpfClientInfo.WriteInfoLog($"{dbName} 共检索命中册记录 {hitcount} 条");

                    // 把超时时间改短一点
                    channel.Timeout = TimeSpan.FromSeconds(20);

                    DateTime search_time = DateTime.Now;

                    int skip_count  = 0;
                    int error_count = 0;

                    if (hitcount > 0)
                    {
                        string strStyle = "id,cols,format:@coldef:*/barcode|*/location|*/uid";

                        // 获取和存储记录
                        ResultSetLoader loader = new ResultSetLoader(channel,
                                                                     null,
                                                                     null,
                                                                     strStyle, // $"id,xml,timestamp",
                                                                     "zh");

                        // loader.Prompt += this.Loader_Prompt;
                        int i = 0;
                        foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader)
                        {
                            if (token.IsCancellationRequested)
                            {
                                return new NormalResult
                                       {
                                           Value     = -1,
                                           ErrorInfo = "用户中断"
                                       }
                            }
                            ;

                            if (record.Cols != null)
                            {
                                string barcode = "";

                                if (record.Cols.Length > 0)
                                {
                                    barcode = record.Cols[0];
                                }
                                string location = "";
                                if (record.Cols.Length > 1)
                                {
                                    location = record.Cols[1];
                                }
                                string uid = "";
                                if (record.Cols.Length > 2)
                                {
                                    uid = record.Cols[2];
                                }
                                if (string.IsNullOrEmpty(barcode) == false &&
                                    string.IsNullOrEmpty(uid) == false)
                                {
                                    uid_table[uid] = barcode;
                                }
                            }

                            i++;
                        }
                    }

                    WpfClientInfo.WriteInfoLog($"dbName='{dbName}'。skip_count={skip_count}, error_count={error_count}");
                }
                return(new NormalResult
                {
                    Value = uid_table.Count,
                });
            }
            catch (Exception ex)
            {
                WpfClientInfo.WriteErrorLog($"DownloadItemRecordAsync() 出现异常:{ExceptionUtil.GetDebugText(ex)}");

                return(new NormalResult
                {
                    Value = -1,
                    ErrorInfo = $"DownloadItemRecordAsync() 出现异常:{ex.Message}"
                });
            }
            finally
            {
                channel.Timeout = old_timeout;
                App.CurrentApp.ReturnChannel(channel);

                WpfClientInfo.WriteInfoLog($"结束下载全部读者记录到本地缓存");
            }
        }