Пример #1
0
        private static void Zserver_GetZConfig(object sender, GetZConfigEventArgs e)
        {
            ZServerChannel zserver_channel = (ZServerChannel)sender;

#if NO
            List <string> parts           = StringUtil.ParseTwoPart(e.Info.m_strID, "@");
            string        strInstanceName = parts[1];
#endif
            string strInstanceName = zserver_channel.SetProperty().GetKeyValue("i_n");
            if (strInstanceName == null)
            {
                string strError = "通道中 实例名 '" + strInstanceName + "' 尚未初始化";
                ZManager.Log.Error(strError);
                e.ZConfig          = null;
                e.Result.ErrorInfo = strError;
                return;
            }

            Instance instance = FindInstance(strInstanceName);
            if (instance == null)
            {
                e.ZConfig          = null;
                e.Result.ErrorInfo = "以用户名 '" + e.Info.m_strID + "' 中包含的实例名 '" + strInstanceName + "' 没有找到任何实例";
                return;
            }

            // 让 channel 携带 Instance Name
            // zserver_channel.SetProperty().SetKeyValue("i_n", strInstanceName);

            e.ZConfig = new ZConfig
            {
                AnonymousUserName = instance.zhost.AnonymousUserName,
                AnonymousPassword = instance.zhost.AnonymousPassword,
            };
        }
Пример #2
0
        // 记忆全局结果集名
        // return:
        //      false   正常
        //      true    结果集数量超过 MAX_RESULTSET_COUNT,返回前已经开始释放所有结果集
        static bool MemoryResultSetName(ZServerChannel zserver_channel,
                                        string resultset_name)
        {
            if (zserver_channel == null)
            {
                throw new ArgumentException("zserver_channel 为空");
            }

            if (!(zserver_channel.EnsureProperty().GetKeyObject("r_n") is List <string> names))
            {
                names = new List <string>();
                zserver_channel.EnsureProperty().SetKeyObject("r_n", names);
            }

            if (names.IndexOf(resultset_name) == -1)
            {
                names.Add(resultset_name);
            }

            // 如果结果集名数量太多,就要开始删除
            if (names.Count > MAX_RESULTSET_COUNT)
            {
                FreeGlobalResultSets(zserver_channel, names);
                // 2018/9/28
                names = new List <string>();
                zserver_channel.EnsureProperty().SetKeyObject("r_n", names);
                return(true);
            }

            return(false);
        }
Пример #3
0
        private static void Zserver_InitializeLogin(object sender, InitializeLoginEventArgs e)
        {
            ZServerChannel zserver_channel = (ZServerChannel)sender;

            string strInstanceName = zserver_channel.SetProperty().GetKeyValue("i_n");

            if (strInstanceName == null)
            {
                string strErrorText = "通道中 实例名 '" + strInstanceName + "' 尚未初始化";
                ZManager.Log?.Error(strErrorText);
                e.Result = new Result {
                    Value = -1, ErrorInfo = strErrorText
                };
                return;
            }
            Instance instance = FindInstance(strInstanceName);

            if (instance == null)
            {
                e.Result = new Result {
                    Value = -1, ErrorInfo = "实例名 '" + strInstanceName + "' 不存在"
                };
                return;
            }

            // result.Value:
            //      -1  登录出错
            //      0   登录未成功
            //      1   登录成功

            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 strParameters = "";
                if (login_info.UserType == "patron")
                {
                    strParameters += ",type=reader";
                }
                strParameters += ",client=dp2capo|" + "0.01";

                long lRet = library_channel.Login(strUserName,
                                                  strPassword,
                                                  strParameters,
                                                  out string strError);
                e.Result.Value     = (int)lRet;
                e.Result.ErrorInfo = strError;
            }
            finally
            {
                instance.MessageConnection.ReturnChannel(library_channel);
            }
        }
Пример #4
0
        static void FreeGlobalResultSets(ZServerChannel zserver_channel,
                                         List <string> names)
        {
            if (zserver_channel == null)
            {
                throw new ArgumentException("zserver_channel 为空");
            }

            string strInstanceName = zserver_channel.EnsureProperty().GetKeyValue("i_n");

            if (strInstanceName == null)
            {
                LibraryManager.Log?.Error("通道中 实例名 'i_n' 尚未初始化");   // ?? bug
            }
            Instance instance = FindZ3950Instance(strInstanceName, out string strError);

            if (instance == null)
            {
                if (string.IsNullOrEmpty(strError))
                {
                    strError = "实例名 '" + strInstanceName + "' 不存在(或实例没有启用 Z39.50 服务)";
                }
                // 写入错误日志
                LibraryManager.Log?.Error(strError);
                return;
            }

            // 交给 Instance 释放
            instance.AddGlobalResultSets(names);

#if NO
            LibraryChannel library_channel = instance.MessageConnection.GetChannel(null);
            try
            {
                foreach (string name in names)
                {
                    // TODO: 要是能用通配符来删除大量结果集就好了
                    long lRet = library_channel.GetSearchResult("",
                                                                0,
                                                                0,
                                                                "@remove:" + name,
                                                                "zh",
                                                                out DigitalPlatform.LibraryClient.localhost.Record[] searchresults,
                                                                out string strError);
                    if (lRet == -1)
                    {
                        // 写入错误日志
                        return;
                    }
                }
            }
            finally
            {
                instance.MessageConnection.ReturnChannel(library_channel);
            }
#endif
        }
Пример #5
0
        private static void Channel_Closed(object sender, EventArgs e)
        {
            ZServerChannel channel = (ZServerChannel)sender;

            channel.Closed -= Channel_Closed;   // 避免重入

            List <string> names = GetResultSetNameList(channel, true);

            if (names.Count > 0)
            {
                FreeGlobalResultSets(channel, names);
            }
        }
Пример #6
0
        static void FreeGlobalResultSets(ZServerChannel zserver_channel,
                                         List <string> names)
        {
            string strInstanceName = zserver_channel.SetProperty().GetKeyValue("i_n");

            if (strInstanceName == null)
            {
                string strError = "通道中 实例名 '" + strInstanceName + "' 尚未初始化";
                ZManager.Log?.Error(strError);
            }
            Instance instance = FindInstance(strInstanceName);

            if (instance == null)
            {
                string strError = "实例名 '" + strInstanceName + "' 不存在";
                // 写入错误日志
                ZManager.Log?.Error(strError);
                return;
            }

            // TODO: 交给 Instance 释放
            instance.AddGlobalResultSets(names);

#if NO
            LibraryChannel library_channel = instance.MessageConnection.GetChannel(null);
            try
            {
                foreach (string name in names)
                {
                    // TODO: 要是能用通配符来删除大量结果集就好了
                    long lRet = library_channel.GetSearchResult("",
                                                                0,
                                                                0,
                                                                "@remove:" + name,
                                                                "zh",
                                                                out DigitalPlatform.LibraryClient.localhost.Record[] searchresults,
                                                                out string strError);
                    if (lRet == -1)
                    {
                        // 写入错误日志
                        return;
                    }
                }
            }
            finally
            {
                instance.MessageConnection.ReturnChannel(library_channel);
            }
#endif
        }
Пример #7
0
        private static void Zserver_SetChannelProperty(object sender, SetChannelPropertyEventArgs e)
        {
            ZServerChannel zserver_channel = (ZServerChannel)sender;

            List <string> parts           = StringUtil.ParseTwoPart(e.Info.m_strID, "@");
            string        strUserName     = parts[0];
            string        strInstanceName = parts[1];

            string strPassword = e.Info.m_strPassword;

            // 匿名登录情形
            if (string.IsNullOrEmpty(strUserName))
            {
                Instance instance = FindInstance(strInstanceName);
                if (instance == null)
                {
                    e.Result = new Result {
                        Value     = -1,
                        ErrorCode = "InstanceNotFound",
                        ErrorInfo = "以用户名 '" + e.Info.m_strID + "' 中包含的实例名 '" + strInstanceName + "' 没有找到任何实例"
                    };
                    return;
                }

                // 如果定义了允许匿名登录
                if (String.IsNullOrEmpty(instance.zhost.AnonymousUserName) == false)
                {
                    strUserName = instance.zhost.AnonymousUserName;
                    strPassword = instance.zhost.AnonymousPassword;
                }
                else
                {
                    e.Result = new Result {
                        Value     = -1,
                        ErrorCode = "AnonymouseLoginDenied",
                        ErrorInfo = "不允许匿名登录"
                    };
                    return;
                }
            }

            // 让 channel 从此携带 Instance Name
            zserver_channel.SetProperty().SetKeyValue("i_n", strInstanceName);
            zserver_channel.SetProperty().SetKeyValue("i_u", strUserName);
            zserver_channel.SetProperty().SetKeyValue("i_p", strPassword);

            Debug.Assert(e.Result != null, "");
        }
Пример #8
0
 // 取出先前记忆的全局结果集名列表
 // parameters:
 //      bRemove 是否在返回前自动删除 key_object 集合中的值
 static List <string> GetResultSetNameList(ZServerChannel zserver_channel,
                                           bool bRemove = false)
 {
     lock (zserver_channel)
     {
         if (!(zserver_channel.EnsureProperty().GetKeyObject("r_n") is List <string> names))
         {
             return(new List <string>());
         }
         else
         {
             if (bRemove)
             {
                 zserver_channel.EnsureProperty().SetKeyObject("r_n", null);
             }
         }
         return(names);
     }
 }
Пример #9
0
        // 记忆全局结果集名
        static void MemoryResultSetName(ZServerChannel zserver_channel,
                                        string resultset_name)
        {
            if (!(zserver_channel.SetProperty().GetKeyObject("r_n") is List <string> names))
            {
                names = new List <string>();
                zserver_channel.SetProperty().SetKeyObject("r_n", names);
            }

            if (names.IndexOf(resultset_name) == -1)
            {
                names.Add(resultset_name);
            }

            // 如果结果集名数量太多,就要开始删除
            if (names.Count > MAX_RESULTSET_COUNT)
            {
                FreeGlobalResultSets(zserver_channel, names);
            }
        }
Пример #10
0
        private static void Channel_Closed(object sender, EventArgs e)
        {
            ZServerChannel channel = (ZServerChannel)sender;

            channel.Closed -= Channel_Closed;   // 避免重入

            // 中断正在进行的检索
            LibraryChannel library_channel = (LibraryChannel)channel.Tag;

            if (library_channel != null)
            {
                library_channel.Abort();
                LibraryManager.Log?.Info(string.Format("ZServerChannel({0}) Channel_Closed() 引发 LibraryChannel.Abort()", channel.GetHashCode()));
            }

            List <string> names = GetResultSetNameList(channel, true);

            if (names.Count > 0)
            {
                FreeGlobalResultSets(channel, names);
            }
        }
Пример #11
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;
            }
        }
Пример #12
0
 // 构造全局结果集名
 static string MakeGlobalResultSetName(ZServerChannel zserver_channel, string strResultSetName)
 {
     return("#" + zserver_channel.GetHashCode() + "_" + strResultSetName);
 }
Пример #13
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;
            }
        }
Пример #14
0
        private static void Zserver_ChannelOpened(object sender, EventArgs e)
        {
            ZServerChannel channel = (ZServerChannel)sender;

            channel.Closed += Channel_Closed;
        }
Пример #15
0
        private static void Zserver_InitializeLogin(object sender, InitializeLoginEventArgs e)
        {
            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)
            {
                string strErrorText = "通道中 实例名 'i_n' 尚未初始化";    // ?? bug
                LibraryManager.Log?.Error(strErrorText);
                e.Result = new Result
                {
                    Value     = -1,
                    ErrorCode = "2",
                    ErrorInfo = strErrorText
                };
                return;
            }
            Instance instance = FindZ3950Instance(strInstanceName, out string strError);

            if (instance == null)
            {
                if (string.IsNullOrEmpty(strError))
                {
                    strError = "实例名 '" + strInstanceName + "' 不存在(或实例没有启用 Z39.50 服务)";
                }
                e.Result = new Result
                {
                    Value     = -1,
                    ErrorCode = "",
                    ErrorInfo = strError
                };
                return;
            }
            if (instance.Running == false)
            {
                e.Result = new Result
                {
                    Value     = -1,
                    ErrorCode = "1019", // Init/AC: System not available due to maintenance
                    ErrorInfo = "实例 '" + instance.Name + "' 正在维护中,暂时不能访问"
                };
                return;
            }

            // TODO: TcpClient 可能为 null, 表示通道已经被切断
            string strClientIP = ZServer.GetClientIP(zserver_channel.TcpClient);

            // testing
            // strClientIP = "127.0.0.2";

            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);

            try
            {
                string strParameters = "";
                if (login_info.UserType == "patron")
                {
                    strParameters += ",type=reader";
                }
                strParameters += ",client=dp2capo|" + "0.01" + ",clientip=" + strClientIP;

                // result.Value:
                //      -1  登录出错
                //      0   登录未成功
                //      1   登录成功
                long lRet = library_channel.Login(login_info.UserName,
                                                  login_info.Password, // strPassword,
                                                  strParameters,
                                                  out strError);
                e.Result.Value = (int)lRet;
                if (lRet != 1)
                {
                    e.Result.ErrorCode = "101";
                }
                e.Result.ErrorInfo = strError;
            }
            finally
            {
                instance.MessageConnection.ReturnChannel(library_channel);
            }
        }
Пример #16
0
        private static void Zserver_SearchSearch(object sender, SearchSearchEventArgs e)
        {
            string strError   = "";
            int    nCondition = 100;

            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)
            {
                string strErrorText = "通道中 实例名 'i_n' 尚未初始化";    // ?? bug
                LibraryManager.Log?.Error(strErrorText);
                e.Result = new DigitalPlatform.Z3950.ZClient.SearchResult {
                    Value = -1, ErrorInfo = strErrorText
                };
                return;
            }
            Instance instance = FindZ3950Instance(strInstanceName, out strError);

            if (instance == null)
            {
                if (string.IsNullOrEmpty(strError))
                {
                    strError = "实例名 '" + strInstanceName + "' 不存在(或实例没有启用 Z39.50 服务)";
                }
                e.Result = new DigitalPlatform.Z3950.ZClient.SearchResult {
                    Value = -1, ErrorInfo = strError
                };
                return;
            }
            if (instance.Running == false)
            {
                strError   = "实例 '" + instance.Name + "' 正在维护中,暂时不能访问";
                nCondition = 1019;  // Init/AC: System not available due to maintenance
                goto ERROR1;
            }

            // 检查实例是否有至少一个可用数据库
            if (instance.zhost.GetDbCount() == 0)
            {
#if NO
                string     strErrorText = "实例 '" + strInstanceName + "' 没有提供可检索的数据库";
                DiagFormat diag         = null;
                ZProcessor.SetPresentDiagRecord(ref diag,
                                                1017, // Init/AC: No databases available for specified userId
                                                strErrorText);
                e.Diag   = diag;
                e.Result = new ZClient.SearchResult {
                    Value = -1, ErrorInfo = strErrorText
                };
                return;
#endif
                strError   = "实例 '" + instance.Name + "' 没有提供可检索的数据库";
                nCondition = 1017;// Init/AC: No databases available for specified userId
                goto ERROR1;
            }

            // 根据逆波兰表构造出 dp2 系统检索式
            // return:
            //      -1  出错
            //      0   数据库没有找到
            //      1   成功
            int nRet = Z3950Utility.BuildQueryXml(
                instance.zhost,
                e.Request.m_dbnames,
                e.Request.m_rpnRoot,
                zserver_channel.EnsureProperty().SearchTermEncoding,
                out string strQueryXml,
                out strError);
            if (nRet == -1 || nRet == 0)
            {
#if NO
                DiagFormat diag = null;
                ZProcessor.SetPresentDiagRecord(ref diag,
                                                nRet == -1 ? 2 : 235, // 2:temporary system error; 235:Database does not exist (database name)
                                                strError);
                e.Diag   = diag;
                e.Result = new ZClient.SearchResult {
                    Value = -1, ErrorInfo = strError
                };
                return;
#endif
                nCondition = nRet == -1 ? 2 : 235;  // 2:temporary system error; 235:Database does not exist (database name)
                goto ERROR1;
            }

            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);
            try
            {
                // TODO: 附加到 Abort 事件。这样当事件被触发的时候,能执行 library_channel.Abort

                // 全局结果集名
                string resultset_name = MakeGlobalResultSetName(zserver_channel, e.Request.m_strResultSetName);

                DateTime start = DateTime.Now;
                // 进行检索
                long lRet = 0;

                zserver_channel.Tag = library_channel;
                try
                {
                    lRet = library_channel.Search(
                        strQueryXml,
                        resultset_name,
                        "", // strOutputStyle
                        out strError);
                }
                finally
                {
                    zserver_channel.Tag = null;
                }

                // testing System.Threading.Thread.Sleep(TimeSpan.FromSeconds(6));
                TimeSpan length = DateTime.Now - start;
                if (length >= slow_length)
                {
                    // TODO: TcpClient 可能为 null, 表示通道已经被切断
                    //string ip = TcpServer.GetClientIP(zserver_channel.TcpClient);
                    //string strChannelName = "ip:" + ip + ",channel:" + zserver_channel.GetHashCode();

                    LibraryManager.Log?.Info("通道 " + zserver_channel.GetDebugName(zserver_channel.TcpClient) + " 检索式 '" + strQueryXml + "' 检索耗时 " + length.ToString() + " (命中记录 " + lRet + "),超过慢速阈值");
                }

                if (lRet == -1)
                {
                    LibraryManager.Log?.Error("通道 " + zserver_channel.GetDebugName(zserver_channel.TcpClient) + " 检索式 '" + strQueryXml + "' 检索出错: " + strError);
                }


                /*
                 * // 测试检索失败
                 * lRet = -1;
                 * strError = "测试检索失败";
                 * */

                if (lRet == -1)
                {
#if NO
                    DiagFormat diag = null;
                    ZProcessor.SetPresentDiagRecord(ref diag,
                                                    2, // temporary system error
                                                    strError);
                    e.Diag   = diag;
                    e.Result = new ZClient.SearchResult {
                        Value = -1, ErrorInfo = strError
                    };
                    return;
#endif
                    goto ERROR1;
                }
                else
                {
                    // 记忆结果集名
                    // return:
                    //      false   正常
                    //      true    结果集数量超过 MAX_RESULTSET_COUNT,返回前已经开始释放所有结果集
                    if (MemoryResultSetName(zserver_channel, resultset_name) == true)
                    {
#if NO
                        DiagFormat diag = null;
                        ZProcessor.SetPresentDiagRecord(ref diag,
                                                        112,       // Too many result sets created (maximum)
                                                        strError); // TODO: 应为 MAX_RESULTSET_COUNT
                        e.Diag   = diag;
                        e.Result = new ZClient.SearchResult {
                            Value = -1, ErrorInfo = strError
                        };
                        return;
#endif
                        nCondition = 112;  // Too many result sets created (maximum)
                        goto ERROR1;
                    }

                    e.Result = new ZClient.SearchResult {
                        ResultCount = lRet
                    };
                }
                return;
            }
            finally
            {
                instance.MessageConnection.ReturnChannel(library_channel);
            }
ERROR1:
            {
                DiagFormat diag = null;
                ZProcessor.SetPresentDiagRecord(ref diag,
                                                nCondition,
                                                strError);
                e.Diag   = diag;
                e.Result = new ZClient.SearchResult {
                    Value = -1, ErrorInfo = strError
                };
                return;
            }
        }
Пример #17
0
        // 处理一个通道的通讯活动
        public virtual void HandleClient(TcpClient tcpClient,
                                         Action close_action,
                                         CancellationToken token)
        {
#if NO
            ZServerChannel channel = _zChannels.Add(tcpClient);
            // 允许对 channel 做额外的初始化
            if (this.ChannelOpened != null)
            {
                this.ChannelOpened(channel, new EventArgs());
            }
            try
            {
                string ip = "";

                try
                {
                    ip = GetClientIP(tcpClient);
                    channel.Touch();

                    int  i       = 0;
                    bool running = true;
                    while (running)
                    {
                        if (token != null && token.IsCancellationRequested)
                        {
                            return;
                        }
                        // 注意调用返回后如果发现返回 null 或者抛出了异常,调主要主动 Close 和重新分配 TcpClient
                        BerTree request = await ZProcessor.GetIncomingRequest(tcpClient);

                        if (request == null)
                        {
                            Console.WriteLine("client close on request " + i);
                            break;
                        }
                        Console.WriteLine("request " + i);

                        channel.Touch();
                        if (token != null && token.IsCancellationRequested)
                        {
                            return;
                        }

                        byte[] response = null;
                        if (this.ProcessRequest == null)
                        {
                            response = await DefaultProcessRequest(channel, request);
                        }
                        else
                        {
                            ProcessRequestEventArgs e = new ProcessRequestEventArgs();
                            e.Request = request;
                            this.ProcessRequest(channel, e);
                            response = e.Response;
                        }

                        channel.Touch();
                        if (token != null && token.IsCancellationRequested)
                        {
                            return;
                        }

                        // 注意调用返回 result.Value == -1 情况下,要及时 Close TcpClient
                        Result result = await SendResponse(response, tcpClient);

                        channel.Touch();
                        if (result.Value == -1)
                        {
                            Console.WriteLine("error on response " + i + ": " + result.ErrorInfo);
                            break;
                        }

                        i++;
                    }
                }
                catch (Exception ex)
                {
                    string strError = "ip:" + ip + " HandleClient() 异常: " + ExceptionUtil.GetExceptionText(ex);
                    ZManager.Log?.Error(strError);
                    // Console.WriteLine(strError);
                }
                finally
                {
                    // tcpClient.Close();
                    // 清除全局结果集
                }
            }
            finally
            {
                _zChannels.Remove(channel);
                channel.Close();
                close_action.Invoke();
            }
#endif
        }
Пример #18
0
        private static void Zserver_SearchSearch(object sender, SearchSearchEventArgs e)
        {
            ZServerChannel zserver_channel = (ZServerChannel)sender;

            string strInstanceName = zserver_channel.SetProperty().GetKeyValue("i_n");

            if (strInstanceName == null)
            {
                string strErrorText = "通道中 实例名 '" + strInstanceName + "' 尚未初始化";
                ZManager.Log?.Error(strErrorText);
                e.Result = new DigitalPlatform.Z3950.ZClient.SearchResult {
                    Value = -1, ErrorInfo = strErrorText
                };
                return;
            }
            Instance instance = FindInstance(strInstanceName);

            if (instance == null)
            {
                e.Result = new DigitalPlatform.Z3950.ZClient.SearchResult {
                    Value = -1, ErrorInfo = "实例名 '" + strInstanceName + "' 不存在"
                };
                return;
            }

            // 根据逆波兰表构造出 dp2 系统检索式

            // return:
            //      -1  error
            //      0   succeed
            int nRet = Z3950Utility.BuildQueryXml(
                instance.zhost,
                e.Request.m_dbnames,
                e.Request.m_rpnRoot,
                zserver_channel.SetProperty().SearchTermEncoding,
                out string strQueryXml,
                out string strError);

            if (nRet == -1)
            {
                DiagFormat diag = null;
                ZProcessor.SetPresentDiagRecord(ref diag,
                                                2, // temporary system error
                                                strError);
                e.Diag   = diag;
                e.Result = new ZClient.SearchResult {
                    Value = -1, ErrorInfo = strError
                };
                return;
            }

            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, e.Request.m_strResultSetName);
                // 进行检索
                long lRet = library_channel.Search(
                    strQueryXml,
                    resultset_name,
                    "", // strOutputStyle
                    out strError);

                /*
                 * // 测试检索失败
                 * lRet = -1;
                 * strError = "测试检索失败";
                 * */

                if (lRet == -1)
                {
                    DiagFormat diag = null;
                    ZProcessor.SetPresentDiagRecord(ref diag,
                                                    2, // temporary system error
                                                    strError);
                    e.Diag   = diag;
                    e.Result = new ZClient.SearchResult {
                        Value = -1, ErrorInfo = strError
                    };
                    return;
                }
                else
                {
                    // 记忆结果集名
                    MemoryResultSetName(zserver_channel, resultset_name);

                    e.Result = new ZClient.SearchResult {
                        ResultCount = lRet
                    };
                }
            }
            finally
            {
                instance.MessageConnection.ReturnChannel(library_channel);
            }
        }