Exemplo n.º 1
0
        // 删除事项记录的操作
        int DoOperDelete(
            SessionInfo sessioninfo,
            bool bForce,
            RmsChannel channel,
            EntityInfo info,
            List<string> oldLocateParams,
            /*
            string strIssueDbName,
            string strParentID,
            string strOldPublishTime,
             * */
            XmlDocument domOldRec,
            ref XmlDocument domOperLog,
            ref List<EntityInfo> ErrorInfos)
        {
            int nRedoCount = 0;
            EntityInfo error = null;
            int nRet = 0;
            long lRet = 0;
            string strError = "";

            /*
            // 如果newrecpath为空但是oldrecpath有值,就用oldrecpath的值
            // 2007/10/23
            if (String.IsNullOrEmpty(info.NewRecPath) == true)
            {
                if (String.IsNullOrEmpty(info.OldRecPath) == false)
                    info.NewRecPath = info.OldRecPath;
            }*/

            // 2008/6/24
            if (String.IsNullOrEmpty(info.NewRecPath) == false)
            {
                if (info.NewRecPath != info.OldRecPath)
                {
                    strError = "action为delete时, 如果info.NewRecPath不空,则其内容必须和info.OldRecPath一致。(info.NewRecPath='" + info.NewRecPath + "' info.OldRecPath='" + info.OldRecPath + "')";
                    return -1;
                }
            }
            else
            {
                info.NewRecPath = info.OldRecPath;
            }


            string strText = "";
            // 构造定位提示信息。用于报错。
            nRet = GetLocateText(
                oldLocateParams,
                out strText,
                out strError);
            if (nRet == -1)
            {
                strError = "GetLocateText()函数报错: " + strError;
                goto ERROR1;
            }

            // 如果记录路径为空, 则先获得记录路径
            if (String.IsNullOrEmpty(info.NewRecPath) == true)
            {
                List<string> aPath = null;

                nRet = IsLocateParamNullOrEmpty(
                    oldLocateParams,
                    out strError);
                if (nRet == -1)
                    goto ERROR1;
                if (nRet == 1)
                {
                    strError += "info.OldRecord中的" + strError + " 和 info.RecPath参数值为空,同时出现,这是不允许的";
                    goto ERROR1;
                }

                /*
                RmsChannel channel = sessioninfo.Channels.GetChannel(this.App.WsUrl);
                if (channel == null)
                {
                    strError = "get channel error";
                    goto ERROR1;
                }
                 * */

                // 本函数只负责查重, 并不获得记录体
                // return:
                //      -1  error
                //      其他    命中记录条数(不超过nMax规定的极限)
                nRet = this.SearchItemRecDup(
                    //  sessioninfo.Channels,
                    channel,
                    oldLocateParams,
                    100,
                    out aPath,
                    out strError);
                if (nRet == -1)
                {
                    strError = "删除操作中事项查重阶段发生错误:" + strError;
                    goto ERROR1;
                }


                if (nRet == 0)
                {
                    error = new EntityInfo(info);
                    error.ErrorInfo = strText + " 的记录已不存在";
                    error.ErrorCode = ErrorCodeValue.NotFound;
                    ErrorInfos.Add(error);
                    return -1;
                }

                if (nRet > 1)
                {
                    /*
                    string[] pathlist = new string[aPath.Count];
                    aPath.CopyTo(pathlist);
                     * */

                    strError = strText + " 已经被下列多条事项记录使用了: " + StringUtil.MakePathList(aPath)/*String.Join(",", pathlist)*/ + "',这是一个严重的系统故障,请尽快通知系统管理员处理。";
                    goto ERROR1;
                }

                info.NewRecPath = aPath[0];
            }

            Debug.Assert(String.IsNullOrEmpty(info.NewRecPath) == false, "");
            // Debug.Assert(strEntityDbName != "", "");

            byte[] exist_timestamp = null;
            string strOutputPath = "";
            string strMetaData = "";
            string strExistingXml = "";

        REDOLOAD:

            // 先读出数据库中此位置的已有记录
            lRet = channel.GetRes(info.NewRecPath,
                out strExistingXml,
                out strMetaData,
                out exist_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                if (channel.ErrorCode == ChannelErrorCode.NotFound)
                {
                    error = new EntityInfo(info);
                    error.ErrorInfo = strText + " 的事项记录 '" + info.NewRecPath + "' 已不存在";
                    error.ErrorCode = channel.OriginErrorCode;
                    ErrorInfos.Add(error);
                    return -1;
                }
                else
                {
                    error = new EntityInfo(info);
                    error.ErrorInfo = "删除操作发生错误, 在读入原有记录 '" + info.NewRecPath + "' 阶段:" + strError;
                    error.ErrorCode = channel.OriginErrorCode;
                    ErrorInfos.Add(error);
                    return -1;
                }
            }

            // 把记录装入DOM
            XmlDocument domExist = new XmlDocument();

            try
            {
                domExist.LoadXml(strExistingXml);
            }
            catch (Exception ex)
            {
                strError = "strExistXml装载进入DOM时发生错误: " + ex.Message;
                goto ERROR1;
            }

            // 观察已存在的记录中,唯一性字段是否和要求的一致
        // return:
        //      -1  出错
        //      0   一致
        //      1   不一致。报错信息在strError中
            nRet = IsLocateInfoCorrect(
                oldLocateParams,
                domExist,
                out strError);
            if (nRet != 0)
                goto ERROR1;

            if (bForce == false)
            {
                // 观察已经存在的记录是否有流通信息
                // return:
                //      -1  出错
                //      0   没有
                //      1   有。报错信息在strError中
                nRet = HasCirculationInfo(domExist,
                    out strError);
                if (nRet != 0)
                    goto ERROR1;
            }

            if (bForce == false)
            {
                // 记录是否允许删除?
                // return:
                //      -1  出错。不允许删除。
                //      0   不允许删除,因为权限不够等原因。原因在strError中
                //      1   可以删除
                nRet = CanDelete(
                    sessioninfo,
                    domExist,
                    out strError);
                if (nRet != 1)
                    goto ERROR1;
            }


            // 比较时间戳
            // 观察时间戳是否发生变化
            nRet = ByteArray.Compare(info.OldTimestamp, exist_timestamp);
            if (nRet != 0)
            {
                // 2008/10/19
                if (bForce == true)
                {
                    error = new EntityInfo(info);
                    error.NewTimestamp = exist_timestamp;   // 让前端知道库中记录实际上发生过变化
                    error.ErrorInfo = "数据库中即将删除的册记录已经发生了变化,请重新装载、仔细核对后再行删除。";
                    error.ErrorCode = ErrorCodeValue.TimestampMismatch;
                    ErrorInfos.Add(error);
                    return -1;
                }

                // 如果前端给出了旧记录,就有和库中记录进行比较的基础
                if (String.IsNullOrEmpty(info.OldRecord) == false)
                {
                    // 比较两个记录, 看看和事项要害信息有关的字段是否发生了变化
                    // return:
                    //      0   没有变化
                    //      1   有变化
                    nRet = IsItemInfoChanged(domExist,
                        domOldRec);
                    if (nRet == 1)
                    {

                        error = new EntityInfo(info);
                        error.NewTimestamp = exist_timestamp;   // 让前端知道库中记录实际上发生过变化
                        error.ErrorInfo = "数据库中即将删除的" + this.ItemName + "记录已经发生了变化,请重新装载、仔细核对后再行删除。";
                        error.ErrorCode = ErrorCodeValue.TimestampMismatch;
                        ErrorInfos.Add(error);
                        return -1;
                    }
                }

                info.OldTimestamp = exist_timestamp;
                info.NewTimestamp = exist_timestamp;
            }

            byte[] output_timestamp = null;

            lRet = channel.DoDeleteRes(info.NewRecPath,
                info.OldTimestamp,
                out output_timestamp,
                out strError);
            if (lRet == -1)
            {
                if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                {
                    if (nRedoCount > 10)
                    {
                        strError = "反复删除均遇到时间戳冲突, 超过10次重试仍然失败";
                        goto ERROR1;
                    }
                    // 发现时间戳不匹配
                    // 重复进行提取已存在记录\比较的过程
                    nRedoCount++;
                    goto REDOLOAD;
                }

                error = new EntityInfo(info);
                error.NewTimestamp = output_timestamp;
                error.ErrorInfo = "删除操作发生错误:" + strError;
                error.ErrorCode = channel.OriginErrorCode;
                ErrorInfos.Add(error);
                return -1;
            }
            else
            {
                // 成功
                DomUtil.SetElementText(domOperLog.DocumentElement, "action", "delete");

                // 不创建<record>元素

                // 创建<oldRecord>元素
                XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement,
                    "oldRecord", strExistingXml);
                DomUtil.SetAttr(node, "recPath", info.NewRecPath);


                // 如果删除成功,则不必要在数组中返回表示成功的信息元素了
            }

            return 0;
        ERROR1:
            error = new EntityInfo(info);
            error.ErrorInfo = strError;
            error.ErrorCode = ErrorCodeValue.CommonError;
            ErrorInfos.Add(error);
            return -1;
        }
Exemplo n.º 2
0
		// 删除记录
		// parameters:
		//		strRecordPath	记录路径。如果==null,表示直接用textBox_recPath中当前的内容作为路径
		public void DeleteRecord(string strRecordPath)
		{
			if (strRecordPath != null)
				textBox_recPath.Text = strRecordPath;

			if (textBox_recPath.Text == "")
			{
				MessageBox.Show(this, "路径不能为空");
				return;
			}

			ResPath respath = new ResPath(textBox_recPath.Text);

			Uri uri = null;
			try 
			{
				uri = new Uri(respath.Url);
			}
			catch (Exception ex)
			{
				MessageBox.Show(this, "路径错误: " + ex.Message);
				return;
			}			// 保存到文件
			if (uri.IsFile)
			{
				MessageBox.Show(this, "暂时不支持删除文件");
				return;
			}


			string strText = "你确实要删除位于服务器 '"+respath.Url+"' 上的记录 '"+respath.Path + "' 吗?";

			DialogResult msgResult = MessageBox.Show(this,
				strText,
				"dp2rms",
				MessageBoxButtons.OKCancel,
				MessageBoxIcon.Question,
				MessageBoxDefaultButton.Button2);
				
			if (msgResult != DialogResult.OK) 
			{
				MessageBox.Show(this, "删除操作被放弃...");
				return;
			}

			string strError;
			byte [] baOutputTimeStamp = null;

			// 使用Channel
			RmsChannel channelSave = channel;

			channel = Channels.GetChannel(respath.Url);
			Debug.Assert(channel != null, "Channels.GetChannel 异常");

			try 
			{

                stop.OnStop += new StopEventHandler(this.DoStop);
                stop.Initial("正在删除记录 " + respath.FullPath);
				stop.BeginLoop();


				EnableControlsInLoading(true);

				long lRet = channel.DoDeleteRes(respath.Path,
					this.TimeStamp,
					out baOutputTimeStamp,
					out strError);

				EnableControlsInLoading(false);

				stop.EndLoop();
                stop.OnStop -= new StopEventHandler(this.DoStop);
				stop.Initial("");

				if (lRet == -1) 
				{
					MessageBox.Show(this, "删除记录 '"+respath.Path+"' 失败,原因: "+strError);
					return;
				}

			}
			finally
			{
				channel = channelSave;
			}



			// 如果删除成功,原来时间戳遗留在this.TimeStamp中,也无害

			MessageBox.Show(this, "删除记录 '" + respath.FullPath + "' 成功。");

		}
Exemplo n.º 3
0
        // 复制属于同一书目记录的全部实体记录
        // parameters:
        //      strAction   copy / move
        // return:
        //      -2  目标实体库不存在,无法进行复制或者删除
        //      -1  error
        //      >=0  实际复制或者移动的实体记录数
        public int CopyBiblioChildItems(RmsChannel channel,
            string strAction,
            List<DeleteEntityInfo> entityinfos,
            string strTargetBiblioRecPath,
            XmlDocument domOperLog,
            out string strError)
        {
            strError = "";

            if (entityinfos == null || entityinfos.Count == 0)
                return 0;

            int nOperCount = 0;

            XmlNode root = null;

            if (domOperLog != null)
            {
                root = domOperLog.CreateElement(strAction == "copy" ? "copy" + this.ItemNameInternal + "Records" : "move" + this.ItemNameInternal + "Records");
                domOperLog.DocumentElement.AppendChild(root);
            }

            // 获得目标书目库下属的实体库名
            string strTargetItemDbName = "";
            string strTargetBiblioDbName = ResPath.GetDbName(strTargetBiblioRecPath);
            // return:
            //      -1  出错
            //      0   没有找到
            //      1   找到
            int nRet = this.GetItemDbName(strTargetBiblioDbName,
                out strTargetItemDbName,
                out strError);
            if (nRet == 0 || string.IsNullOrEmpty(strTargetItemDbName) == true)
            {
                return -2;   // 目标实体库不存在
            }

            string strParentID = ResPath.GetRecordId(strTargetBiblioRecPath);
            if (string.IsNullOrEmpty(strParentID) == true)
            {
                strError = "目标书目记录路径 '" + strTargetBiblioRecPath + "' 不正确,无法获得记录号";
                return -1;
            }



            List<string> newrecordpaths = new List<string>();
            List<string> oldrecordpaths = new List<string>();
            for (int i = 0; i < entityinfos.Count; i++)
            {
                DeleteEntityInfo info = entityinfos[i];

                byte[] output_timestamp = null;
                string strOutputRecPath = "";

                // this.EntityLocks.LockForWrite(info.ItemBarcode);
                try
                {
                    XmlDocument dom = new XmlDocument();
                    try
                    {
                        dom.LoadXml(info.OldRecord);
                    }
                    catch (Exception ex)
                    {
                        strError = "记录 '" + info.RecPath + "' 装入XMLDOM发生错误: " + ex.Message;
                        goto ERROR1;
                    }
                    DomUtil.SetElementText(dom.DocumentElement,
                        "parent",
                        strParentID);

                    // 复制的情况
                    if (strAction == "copy")
                    {
                        // 避免refID重复
                        DomUtil.SetElementText(dom.DocumentElement,
                            "refID",
                            null);
                    }

                    long lRet = channel.DoCopyRecord(info.RecPath,
                         strTargetItemDbName + "/?",
                         strAction == "move" ? true : false,   // bDeleteSourceRecord
                         out output_timestamp,
                         out strOutputRecPath,
                         out strError);
                    if (lRet == -1)
                    {
                        if (channel.ErrorCode == ChannelErrorCode.NotFound)
                            continue;
                        strError = "复制" + this.ItemName + "记录 '" + info.RecPath + "' 时发生错误: " + strError;
                        goto ERROR1;
                    }

                    // 2011/5/24
                    // 修改xml记录。<parent>元素发生了变化
                    byte[] baOutputTimestamp = null;
                    string strOutputRecPath1 = "";
                    lRet = channel.DoSaveTextRes(strOutputRecPath,
                        dom.OuterXml,
                        false,
                        "content", // ,ignorechecktimestamp
                        output_timestamp,
                        out baOutputTimestamp,
                        out strOutputRecPath1,
                        out strError);
                    if (lRet == -1)
                        goto ERROR1;

                    oldrecordpaths.Add(info.RecPath);
                    newrecordpaths.Add(strOutputRecPath);
                }
                finally
                {
                    // this.EntityLocks.UnlockForWrite(info.ItemBarcode);
                }

                // 增补到日志DOM中
                if (domOperLog != null)
                {
                    Debug.Assert(root != null, "");

                    XmlNode node = domOperLog.CreateElement("record");
                    root.AppendChild(node);

                    DomUtil.SetAttr(node, "recPath", info.RecPath);
                    DomUtil.SetAttr(node, "targetRecPath", strOutputRecPath);
                }

                nOperCount++;
            }


            return nOperCount;
        ERROR1:
            // Undo已经进行过的操作
            if (strAction == "copy")
            {
                string strWarning = "";

                foreach (string strRecPath in newrecordpaths)
                {
                    string strTempError = "";
                    byte[] timestamp = null;
                    byte[] output_timestamp = null;
                REDO_DELETE:
                    long lRet = channel.DoDeleteRes(strRecPath,
                        timestamp,
                        out output_timestamp,
                        out strTempError);
                    if (lRet == -1)
                    {
                        if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                        {
                            if (timestamp == null)
                            {
                                timestamp = output_timestamp;
                                goto REDO_DELETE;
                            }
                        }
                        strWarning += strTempError + ";";
                    }

                }
                if (string.IsNullOrEmpty(strWarning) == false)
                    strError = strError + "。在Undo过程中,又遇到出错: " + strWarning;
            }
            else if (strAction == "move")
            {
                string strWarning = "";
                for (int i = 0; i < newrecordpaths.Count; i++)
                {
                    byte[] output_timestamp = null;
                    string strOutputRecPath = "";
                    string strTempError = "";
                    long lRet = channel.DoCopyRecord(newrecordpaths[i],
         oldrecordpaths[i],
         true,   // bDeleteSourceRecord
         out output_timestamp,
         out strOutputRecPath,
         out strTempError);
                    if (lRet == -1)
                    {
                        strWarning += strTempError + ";";
                    }
                }
                if (string.IsNullOrEmpty(strWarning) == false)
                    strError = strError + "。在Undo过程中,又遇到出错: " + strWarning;
            }
            return -1;
        }
Exemplo n.º 4
0
        // 删除属于同一书目记录的全部实体记录
        // 这是需要提供EntityInfo数组的版本
        // return:
        //      -1  error
        //      0   没有找到属于书目记录的任何实体记录,因此也就无从删除
        //      >0  实际删除的实体记录数
        public int DeleteBiblioChildItems(
            // RmsChannelCollection Channels,
            RmsChannel channel,
            List<DeleteEntityInfo> entityinfos,
            XmlDocument domOperLog,
            out string strError)
        {
            strError = "";

            if (entityinfos == null || entityinfos.Count == 0)
                return 0;

            int nDeletedCount = 0;

            XmlNode root = null;

            if (domOperLog != null)
            {
                root = domOperLog.CreateElement("deleted"+this.ItemNameInternal+"Records");
                domOperLog.DocumentElement.AppendChild(root);
            }

#if NO
            RmsChannel channel = Channels.GetChannel(this.App.WsUrl);
            if (channel == null)
            {
                strError = "get channel error";
                goto ERROR1;
            }
#endif

            // 真正实行删除
            for (int i = 0; i < entityinfos.Count; i++)
            {
                DeleteEntityInfo info = entityinfos[i];

                byte[] output_timestamp = null;
                int nRedoCount = 0;

            REDO_DELETE:

                // this.EntityLocks.LockForWrite(info.ItemBarcode);
                try
                {

                    long lRet = channel.DoDeleteRes(info.RecPath,
                        info.OldTimestamp,
                        out output_timestamp,
                        out strError);
                    if (lRet == -1)
                    {
                        if (channel.ErrorCode == ChannelErrorCode.NotFound)
                            continue;

                        // 如果不重试,让时间戳出错暴露出来。
                        // 如果要重试,也得加上重新读入册记录并判断重新判断无借还信息才能删除

                        if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                        {
                            if (nRedoCount > 10)
                            {
                                strError = "重试了10次还不行。删除"+this.ItemName+"记录 '" + info.RecPath + "' 时发生错误: " + strError;
                                goto ERROR1;
                            }
                            nRedoCount++;

                            // 重新读入记录
                            string strMetaData = "";
                            string strXml = "";
                            string strOutputPath = "";
                            string strError_1 = "";

                            lRet = channel.GetRes(info.RecPath,
                                out strXml,
                                out strMetaData,
                                out output_timestamp,
                                out strOutputPath,
                                out strError_1);
                            if (lRet == -1)
                            {
                                if (channel.ErrorCode == ChannelErrorCode.NotFound)
                                    continue;

                                strError = "在删除"+this.ItemName+"记录 '" + info.RecPath + "' 时发生时间戳冲突,于是自动重新获取记录,但又发生错误: " + strError_1;
                                goto ERROR1;
                                // goto CONTINUE;
                            }

                            // 检查是否有借阅信息
                            // 把记录装入DOM
                            XmlDocument domExist = new XmlDocument();

                            try
                            {
                                if (String.IsNullOrEmpty(strXml) == false)
                                    domExist.LoadXml(strXml);
                                else
                                    domExist.LoadXml("<root />");
                            }
                            catch (Exception ex)
                            {
                                strError = this.ItemName+"记录 '" + info.RecPath + "' XML装载进入DOM时发生错误: " + ex.Message;
                                goto ERROR1;
                            }

                            /*
                            info.ItemBarcode = DomUtil.GetElementText(domExist.DocumentElement,
                                "barcode");
                             * */

                            // 观察已经存在的记录是否有流通信息
                            // return:
                            //      -1  出错
                            //      0   没有
                            //      1   有。报错信息在strError中
                            int nRet = this.HasCirculationInfo(domExist, out strError);
                            if (nRet == -1)
                                goto ERROR1;
                            if (nRet == 1)
                            {
                                strError = "拟删除的"+this.ItemName+"记录 '" + info.RecPath + "' 中"+strError+"(此种情况可能不限于这一条),不能删除。";
                                goto ERROR1;
                            }

                            info.OldTimestamp = output_timestamp;
                            goto REDO_DELETE;
                        }

                        strError = "删除"+this.ItemName+"记录 '" + info.RecPath + "' 时发生错误: " + strError;
                        goto ERROR1;
                    }
                }
                finally
                {
                    // this.EntityLocks.UnlockForWrite(info.ItemBarcode);
                }

                // 增补到日志DOM中
                if (domOperLog != null)
                {
                    Debug.Assert(root != null, "");

                    XmlNode node = domOperLog.CreateElement("record");
                    root.AppendChild(node);

                    DomUtil.SetAttr(node, "recPath", info.RecPath);
                }

                nDeletedCount++;
            }


            return nDeletedCount;
        ERROR1:
            return -1;
        }
Exemplo n.º 5
0
        // TODO: 各个环节要改为尽量使用 refID。要做大量测试
        // text-level: 内部处理
        // 在 预约到书 库中,追加一条新的记录,并作 email / dpmail / mq 通知
        // 注:本函数可能要删除部分通知记录
        // parameters:
        //      strItemBarcode  册条码号。必须是册条码号。如果册条码号为空,参考ID需要使用 strRefID 参数
        //      strRefID        参考ID
        //      bOnShelf    要通知的册是否在架。在架指并没有人借阅过,本来就在书架上。
        //      strLibraryCode  读者所在的馆代码
        //      strReaderXml    预约了图书的读者的XML记录。用于消息通知接口
        int AddNotifyRecordToQueueDatabase(
            // RmsChannelCollection channels,
            RmsChannel channel,
            string strItemBarcodeParam,
            string strRefIDParam,
            string strItemXml,
            bool bOnShelf,
            string strLibraryCode,
            string strReaderBarcode,
            string strReaderXml,
            out List<string> DeletedNotifyRecPaths,
            out string strError)
        {
            strError = "";
            DeletedNotifyRecPaths = new List<string>();

            // 2010/12/31
            if (String.IsNullOrEmpty(this.ArrivedDbName) == true)
            {
                strError = "预约到书库尚未定义, AddNotifyRecordToQueue()调用失败";
                return -1;
            }

            // 准备写记录
            byte[] timestamp = null;
            byte[] output_timestamp = null;
            string strOutputPath = "";
            int nRet = 0;
            long lRet = 0;

            if (String.IsNullOrEmpty(strItemBarcodeParam) == true)
            {
                // 如果检索用的册条码号为空,加上对命中结果数量不设限,那就会造成系统严重繁忙。
                strError = "参数strItemBarcode中的册条码号不能为空。";
                return -1;
            }

#if NO
            RmsChannel channel = channels.GetChannel(this.WsUrl);
            if (channel == null)
            {
                strError = "get channel error";
                return -1;
            }
#endif

        REDODELETE:
            // 如果队列中已经存在同册条码号的记录, 要先删除
            string strNotifyXml = "";
            // 获得预约到书队列记录
            // return:
            //      -1  error
            //      0   not found
            //      1   命中1条
            //      >1  命中多于1条
            nRet = GetArrivedQueueRecXml(
                // channels,
                channel,
                strItemBarcodeParam,
                out strNotifyXml,
                out timestamp,
                out strOutputPath,
                out strError);
            if (nRet == -1)
            {
                // 写入错误日志?
                this.WriteErrorLog("在还书操作中,检索册条码号为 " + strItemBarcodeParam + " 的预约到书库记录时出错: " + strError);
            }
            if (nRet >= 1)
            {
                int nRedoDeleteCount = 0;
            // TODO: 这一段删除代码可以专门编制在一个函数中,不必这么费力循环。可以优化处理
            REDO_DELETE:
                lRet = channel.DoDeleteRes(strOutputPath,
                    timestamp,
                    out output_timestamp,
                    out strError);
                if (lRet == -1)
                {
                    // 时间戳不匹配
                    if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch
                        && nRedoDeleteCount < 10)
                    {
                        nRedoDeleteCount++;
                        timestamp = output_timestamp;
                        goto REDO_DELETE;
                    }

                    // 写入错误日志?
                    this.WriteErrorLog("在还书操作中,加入新预约到书记录前, 删除已存在的预约到书库记录 '" + strOutputPath + "' 出错: " + strError);
                }

                DeletedNotifyRecPaths.Add(strOutputPath);    // 记忆已经被删除的记录路径 2007/7/5 

                goto REDODELETE;    // 如果有多条,循环删除
            }

            XmlDocument itemdom = null;
            nRet = LibraryApplication.LoadToDom(strItemXml,
                out itemdom,
                out strError);
            if (nRet == -1)
            {
                strError = "装载册记录 '" + strItemBarcodeParam + "' 的 XML 进入 DOM 时发生错误: " + strError;
                return -1;
            }

            string strLocation = DomUtil.GetElementText(itemdom.DocumentElement, "location");
            strLocation = StringUtil.GetPureLocationString(strLocation);

            string strAccessNo = DomUtil.GetElementText(itemdom.DocumentElement, "accessNo");

            /*
  <reservations>
        <request reader="R0000001" requestDate="Mon, 05 Sep 2016 16:57:47 +0800" operator="R0000001" /> 
  </reservations>
             * */
            // 从册记录 reservations 元素下找第一个 request 元素,其 requestDate 属性
            string strRequestDate = "";
            XmlElement request = itemdom.DocumentElement.SelectSingleNode("reservations/request") as XmlElement;
            if (request != null)
                strRequestDate = request.GetAttribute("requestDate");

            // 创建预约到书记录
            XmlDocument new_queue_dom = new XmlDocument();
            new_queue_dom.LoadXml("<root />");

            // TODO: 以后增加 <refID> 元素,存储册记录的参考ID

#if NO
            XmlNode nodeItemBarcode = DomUtil.SetElementText(dom.DocumentElement, "itemBarcode", strItemBarcode);

            // 在<itemBarcode>元素中增加一个onShelf属性,表示属于在架情况
            Debug.Assert(nodeItemBarcode != null, "");
            if (bOnShelf == true)
                DomUtil.SetAttr(nodeItemBarcode, "onShelf", "true");
#endif
            string strItemRefID = "";   // 计划存储纯粹的 refid
            string strItemBarcode = strItemBarcodeParam;    // 计划存储纯粹的册条码号

            // 兼容 strItemBarcode 中含有前缀的用法
            string strHead = "@refID:";
            if (StringUtil.HasHead(strItemBarcodeParam, strHead, true) == true)
            {
                strItemRefID = strItemBarcodeParam.Substring(strHead.Length);
                strItemBarcode = "";
            }

            string strUnionItemBarcode = GetUnionBarcode(strItemBarcode, strItemRefID);

            if (this.ArrivedDbKeysContainsRefIDKey() == true)
            {
                DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", strItemBarcode);
                DomUtil.SetElementText(new_queue_dom.DocumentElement, "refID", strItemRefID);
            }
            else
            {
                if (string.IsNullOrEmpty(strItemBarcode) == true)
                {
                    if (string.IsNullOrEmpty(strItemRefID) == true)
                    {
                        strError = "AddNotifyRecordToQueue() 函数当 strItemBarcode 参数为空的时候,必须让 strRefID 参数不为空";
                        return -1;
                    }

                    Debug.Assert(string.IsNullOrEmpty(strItemRefID) == false, "");
                    // 旧的用法。避免检索时候查不到
                    DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", "@refID:" + strItemRefID);
                }
                else
                    DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", strItemBarcode); // 2015/5/20 添加,修正 BUG
            }

            // 改为存储在元素中 2015/5/7
            if (bOnShelf == true)
                DomUtil.SetElementText(new_queue_dom.DocumentElement, "onShelf", "true");

            // 2012/10/26
            DomUtil.SetElementText(new_queue_dom.DocumentElement, "libraryCode", strLibraryCode);

            DomUtil.SetElementText(new_queue_dom.DocumentElement, "readerBarcode", strReaderBarcode);
            DomUtil.SetElementText(new_queue_dom.DocumentElement, "notifyDate", this.Clock.GetClock());

            // 2015/6/13
            DomUtil.SetElementText(new_queue_dom.DocumentElement, "location", strLocation);

            string strPath = this.ArrivedDbName + "/?";

            // 写新记录
            lRet = channel.DoSaveTextRes(
                strPath,
                new_queue_dom.OuterXml,
                false,
                "content,ignorechecktimestamp",
                timestamp,
                out output_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                // 写入错误日志 2007/1/3 
                this.WriteErrorLog("创建新的预约到书队列记录时出错: " + strError);
                return -1;
            }

            string strReaderEmailAddress = "";
            string strName = "";
            nRet = GetReaderNotifyInfo(
                strReaderXml,
                out strName,
                out strReaderEmailAddress,
                out strError);
            if (nRet == -1)
                return -1;

            // 获得图书摘要信息
            string strSummary = "";     // 没有被截断的摘要字符串
            string strShortSummary = "";    // 截断后的摘要字符串
            string strBiblioRecPath = "";

            nRet = this.GetBiblioSummary(strUnionItemBarcode,
                "", //  strConfirmItemRecPath,
                null,   //  strBiblioRecPathExclude,
                -1, // 25,
                out strBiblioRecPath,
                out strSummary,
                out strError);
            if (nRet == -1)
            {
                strSummary = "ERROR: " + strError;
            }
            else
            {
                strShortSummary = LibraryApplication.CutSummary(strSummary, 25);
            }

#if NO
            // 临时的SessionInfo对象
            SessionInfo sessioninfo = new SessionInfo(this);
            // 模拟一个账户
            Account account = new Account();
            account.LoginName = "CacheBuilder";
            account.Password = "";
            account.Rights = "getbibliosummary";

            account.Type = "";
            account.Barcode = "";
            account.Name = "AddNotifyRecordToQueue";
            account.UserID = "AddNotifyRecordToQueue";
            account.RmsUserName = this.ManagerUserName;
            account.RmsPassword = this.ManagerPassword;

            sessioninfo.Account = account;
            try
            {

                string strBiblioRecPath = "";
                LibraryServerResult result = this.GetBiblioSummary(
                    sessioninfo,
                    strItemBarcode,
                    "", // strConfirmItemRecPath,
                    null,
                    out strBiblioRecPath,
                    out strSummary);
                if (result.Value == -1)
                {
                    strSummary = "ERROR: " + result.ErrorInfo;
                }
                else
                {
                    // 截断
                    if (strSummary.Length > 25)
                        strSummary = strSummary.Substring(0, 25) + "...";
                }
            }
            finally
            {
                sessioninfo.Close();
                sessioninfo = null;
            }
#endif

            // 发送短消息通知
            string strTotalError = "";

            // *** dpmail
            if (this.MessageCenter != null
                && StringUtil.IsInList("dpmail", this.ArrivedNotifyTypes))
            {
                string strTemplate = "";
                // 获得邮件模板
                nRet = GetMailTemplate(
                    "dpmail",
                    bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)",
                    out strTemplate,
                    out strError);
                if (nRet == -1)
                    return -1;
                if (nRet == 0)
                {
                    strError = "预约到书通知<mailTemplate/template>尚未配置。";
                    return -1;
                }

                /*
                %item%  册信息
                %reservetime%   保留期限
                %today% 发出email的当天
                %summary% 书目摘要
                %itembarcode% 册条码号 
                %name% 读者姓名
                 * */
                Hashtable table = new Hashtable();
                table["%item%"] = "(册条码号为: " + strUnionItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strUnionItemBarcode + " )";
                table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan);
                table["%today%"] = DateTime.Now.ToString();
                table["%summary%"] = strShortSummary;
                table["%itembarcode%"] = strUnionItemBarcode;
                table["%name%"] = strName;
                string strBody = "";

                nRet = GetMailText(strTemplate,
                    table,
                    out strBody,
                    out strError);
                if (nRet == -1)
                    return -1;

                if (String.IsNullOrEmpty(this.MessageCenter.MessageDbName) == false)
                {
                    Debug.Assert(channel.Container != null, "");
                    // 发送消息
                    nRet = this.MessageCenter.SendMessage(
                        channel.Container,  // channels,
                        strReaderBarcode,
                        "图书馆",
                        "预约到书通知",
                        "text",
                        strBody,
                        false,
                        out strError);
                    if (nRet == -1)
                    {
                        strTotalError += "发送dpmail消息时出错: " + strError + "\r\n";
                    }
                }
            }

            // 2016/4/26
            // *** mq
            if (string.IsNullOrEmpty(this.OutgoingQueue) == false
                && StringUtil.IsInList("mq", this.ArrivedNotifyTypes))
            {
                XmlDocument dom = new XmlDocument();
                dom.LoadXml("<root />");

                /* 元素名
                 * type 消息类型。预约到书通知
                 * itemBarcode 册条码号
                 * location 馆藏地 2016/9/5
                 * refID    册的参考 ID
                 * onShelf 是否在架。true/false
                 * opacURL  图书在 OPAC 中的 URL。相对路径
                 * requestDate 预约请求创建时间 2016/9/5
                 * reserveTime 保留的时间
                 * today 今天的日期
                 * summary 书目摘要
                 * patronName   读者姓名
                 * patronRecord 读者 XML 记录
 * */
                DomUtil.SetElementText(dom.DocumentElement, "type", "预约到书通知");

                DomUtil.SetElementText(dom.DocumentElement,
                    "itemBarcode", strItemBarcode);
                DomUtil.SetElementText(dom.DocumentElement,
                    "location", strLocation);
                // 2016/11/15
                DomUtil.SetElementText(dom.DocumentElement,
                    "accessNo", strAccessNo);

                // 2016/9/5
                if (string.IsNullOrEmpty(strItemRefID))
                    strItemRefID = DomUtil.GetElementText(itemdom.DocumentElement, "refID");

                DomUtil.SetElementText(dom.DocumentElement,
                    "refID", strItemRefID);
                DomUtil.SetElementText(dom.DocumentElement,
                    "onShelf", bOnShelf ? "true" : "false");

                DomUtil.SetElementText(dom.DocumentElement,
                    "opacURL", this.OpacServerUrl + "/book.aspx?barcode="
                    + strUnionItemBarcode);
                DomUtil.SetElementText(dom.DocumentElement,
                    "requestDate", strRequestDate);
                DomUtil.SetElementText(dom.DocumentElement,
                    "reserveTime", this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan));
                DomUtil.SetElementText(dom.DocumentElement,
                    "today", DateTime.Now.ToString());
                DomUtil.SetElementText(dom.DocumentElement,
                    "summary", strSummary);
                DomUtil.SetElementText(dom.DocumentElement,
                    "patronName", strName);

                string strReaderRefID = "";
                {
                    XmlDocument readerdom = new XmlDocument();
                    readerdom.LoadXml(strReaderXml);

                    strReaderRefID = DomUtil.GetElementText(readerdom.DocumentElement, "refID");

                    XmlElement record = dom.CreateElement("patronRecord");
                    dom.DocumentElement.AppendChild(record);
                    record.InnerXml = readerdom.DocumentElement.InnerXml;

                    DomUtil.DeleteElement(record, "borrowHistory");
                    DomUtil.DeleteElement(record, "password");
                    DomUtil.DeleteElement(record, "fingerprint");
                    DomUtil.SetElementText(record, "libraryCode", strLibraryCode);
                }

                try
                {
                    MessageQueue queue = new MessageQueue(this.OutgoingQueue);

                    // 向 MSMQ 消息队列发送消息
                    nRet = ReadersMonitor.SendToQueue(queue,
                        (string.IsNullOrEmpty(strReaderRefID) ? strReaderBarcode : "!refID:" + strReaderRefID)
                        + "@LUID:" + this.UID,
                        "xml",
                        dom.DocumentElement.OuterXml,
                        out strError);
                    if (nRet == -1)
                    {
                        strTotalError += "发送 MQ 消息时出错: " + strError + "\r\n";
                    }
                }
                catch (Exception ex)
                {
                    strTotalError += "创建路径为 '" + this.OutgoingQueue + "' 的 MessageQueue 对象失败: " + ExceptionUtil.GetDebugText(ex);
                }
            }

            // ** email
            if (String.IsNullOrEmpty(strReaderEmailAddress) == false
                && StringUtil.IsInList("email", this.ArrivedNotifyTypes))
            {
                string strTemplate = "";
                // 获得邮件模板
                nRet = GetMailTemplate(
                    "email",
                    bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)",
                    out strTemplate,
                    out strError);
                if (nRet == -1)
                    return -1;
                if (nRet == 0)
                {
                    strError = "预约到书通知<mailTemplate/template>尚未配置。";
                    return -1;
                }

                /*
                %item%  册信息
                %reservetime%   保留期限
                %today% 发出email的当天
                %summary% 书目摘要
                %itembarcode% 册条码号 
                %name% 读者姓名
                 * */
                Hashtable table = new Hashtable();
                table["%item%"] = "(册条码号为: " + strUnionItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strUnionItemBarcode + " )";
                table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan);
                table["%today%"] = DateTime.Now.ToString();
                table["%summary%"] = strShortSummary;
                table["%itembarcode%"] = strUnionItemBarcode;
                table["%name%"] = strName;

                string strBody = "";

                nRet = GetMailText(strTemplate,
                    table,
                    out strBody,
                    out strError);
                if (nRet == -1)
                    return -1;

                {
                    // 发送email
                    // return:
                    //      -1  error
                    //      0   not found smtp server cfg
                    //      1   succeed
                    nRet = SendEmail(strReaderEmailAddress,
                        "预约到书通知",
                        strBody,
                        "text",
                        out strError);
                    if (nRet == -1)
                    {
                        strTotalError += "发送email消息时出错: " + strError + "\r\n";
                    }
                }
            }

            // *** external messageinterfaces
            if (this.m_externalMessageInterfaces != null)
            {
                foreach (MessageInterface message_interface in this.m_externalMessageInterfaces)
                {
                    // types
                    if (StringUtil.IsInList(message_interface.Type, this.ArrivedNotifyTypes) == false)
                        continue;

                    string strTemplate = "";
                    // 获得邮件模板
                    nRet = GetMailTemplate(
                        message_interface.Type,
                        bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)",
                        out strTemplate,
                        out strError);
                    if (nRet == -1)
                        return -1;
                    if (nRet == 0)
                    {
                        strError = "预约到书通知<mailTemplate/template>尚未配置。";
                        return -1;
                    }

                    /*
                    %item%  册信息
                    %reservetime%   保留期限
                    %today% 发出email的当天
                %summary% 书目摘要
                %itembarcode% 册条码号 
                %name% 读者姓名
                     * */
                    Hashtable table = new Hashtable();
                    table["%item%"] = "(册条码号为: " + strUnionItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strUnionItemBarcode + " )";
                    table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan);
                    table["%today%"] = DateTime.Now.ToString();
                    table["%summary%"] = strShortSummary;
                    table["%itembarcode%"] = strUnionItemBarcode;
                    table["%name%"] = strName;

                    string strBody = "";

                    nRet = GetMailText(strTemplate,
                        table,
                        out strBody,
                        out strError);
                    if (nRet == -1)
                        return -1;

                    // 发送消息
                    nRet = message_interface.HostObj.SendMessage(
                        strReaderBarcode,
                        strReaderXml,
                        strBody,
                        strLibraryCode,
                        out strError);
                    if (nRet == -1)
                    {
                        strTotalError += "发送" + message_interface.Type + "消息时出错: " + strError + "\r\n";
                    }
                }
            }

            if (String.IsNullOrEmpty(strTotalError) == false)
            {
                strError = strTotalError;
                return -1;
            }

            return 0;
        }
Exemplo n.º 6
0
        // text-level: 内部处理
        // 通知下一个预约者,或者(因没有下一个预约者了)而归架
        // 调用前,需要先获得预约队列记录
        // return:
        //      -1  error
        //      0   正常
        //      1   后面已经没有预约者,已通知管理员归架
        public int DoNotifyNext(
            CachedRecordCollection records,
            RmsChannel channel,
            string strQueueRecPath,
            XmlDocument queue_rec_dom,
            byte[] baQueueRecTimeStamp,
            out string strError)
        {
            strError = "";
            long lRet = 0;
            int nRet = 0;

            // RmsChannel channel = null;
            byte[] output_timestamp = null;

            string strState = DomUtil.GetElementText(queue_rec_dom.DocumentElement,
                "state");

            string strNotifyDate = DomUtil.GetElementText(queue_rec_dom.DocumentElement,
                "notifyDate");
            // XmlNode nodeItemBarcode = null;
            string strItemBarcode = DomUtil.GetElementText(queue_rec_dom.DocumentElement,
                "itemBarcode"/*, out nodeItemBarcode*/);

            // 2015/5/7
            string strRefID = DomUtil.GetElementText(queue_rec_dom.DocumentElement,
    "refID");

            string strReaderBarcode = DomUtil.GetElementText(queue_rec_dom.DocumentElement,
                "readerBarcode");

            bool bOnShelf = false;
#if NO
            // <itemBarcode>元素是否有onShelf属性。
            if (nodeItemBarcode != null)
            {
                string strOnShelf = DomUtil.GetAttr(nodeItemBarcode, "onShelf");
                if (strOnShelf.ToLower() == "true"
                    || strOnShelf.ToLower() == "yes"
                    || strOnShelf.ToLower() == "on")
                    bOnShelf = true;
            }
#endif
            // 2015/5/7
            // <onShelf> 元素
            {
                string strOnShelf = DomUtil.GetElementText(queue_rec_dom.DocumentElement, "onShelf");
                if (DomUtil.IsBooleanTrue(strOnShelf, false) == true)
                    bOnShelf = true;
            }

            // 2015/5/7
            if (string.IsNullOrEmpty(strItemBarcode) == true && string.IsNullOrEmpty(strRefID) == false)
            {
                strItemBarcode = "@refID:" + strRefID;
            }

            // 要通知下一位预约者

            string strReservationReaderBarcode = "";

            // 清除读者和册记录中的已到预约事项,并提取下一个预约读者证条码号
            // 本函数还负责清除册记录中以前残留的state=arrived的<request>元素
            nRet = this.ClearArrivedInfo(
                records,
                channel,
                strReaderBarcode,
                strItemBarcode,
                bOnShelf,
                out strReservationReaderBarcode,
                out strError);
            if (nRet == -1)
                return -1;

            // 3) 通知预约到书的操作
            List<string> DeletedNotifyRecPaths = null;  // 被删除的通知记录。

            if (String.IsNullOrEmpty(strReservationReaderBarcode) == false)
            {
                // 通知下一读者

                // 出于对读者库加锁方面的便利考虑, 单独做了此函数
                // return:
                //      -1  error
                //      0   没有找到<request>元素
                //      1   已成功处理
                nRet = this.DoReservationNotify(
                    records,
                    channel,
                    strReservationReaderBarcode,
                    true,
                    strItemBarcode,
                    bOnShelf,
                    false,   // 不要修改当前册记录的<request> state属性,因为前面ClearArrivedInfo()中已经调用了DoItemReturnReservationCheck(), 修改了当前册的<request> state属性。
                    out DeletedNotifyRecPaths,
                    out strError);
                if (nRet == -1)
                    return -1;
            }
            else
            {
                // outof 的记录何时删除?
                // 册记录中的馆藏地点 #reservation何时消除?一个是现在就消除,一个是盘点模块扫描条码时消除。

                // 把记录状态修改为 outofreservation
                DomUtil.SetElementText(queue_rec_dom.DocumentElement,
                    "state",
                    "outof");

                // channel = channels.GetChannel(this.WsUrl);

                string strOutputPath = "";
                lRet = channel.DoSaveTextRes(strQueueRecPath,
                    queue_rec_dom.OuterXml,
                    false,
                    "content,ignorechecktimestamp",
                    baQueueRecTimeStamp,
                    out output_timestamp,
                    out strOutputPath,
                    out strError);
                if (lRet == -1)
                {
                    strError = "写回预约到书记录 '" + strQueueRecPath + "' 时发生错误: " + strError;
                    return -1;
                }

                // TODO: 通知馆员进行上架操作
                // 可以在系统某目录不断追加到一个文本文件,工作人员可以查对。
                // 格式:每行 册条码号 最后一个预约的读者证条码号
                if (String.IsNullOrEmpty(this.StatisDir) == false)
                {
                    string strLogFileName = this.StatisDir + "\\outof_reservation_" + Statis.GetCurrentDate() + ".txt";
                    StreamUtil.WriteText(strLogFileName, strItemBarcode + " " + strReaderBarcode + "\r\n");
                }

                return 1;
            }

            // 4) 删除当前通知记录

            // 2007/7/5 
            bool bAlreadeDeleted = false;
            if (DeletedNotifyRecPaths != null)
            {
                if (DeletedNotifyRecPaths.IndexOf(strQueueRecPath) != -1)
                    bAlreadeDeleted = true;
            }

            if (bAlreadeDeleted == false)
            {
                lRet = channel.DoDeleteRes(
                    strQueueRecPath,
                    baQueueRecTimeStamp,
                    out output_timestamp,
                    out strError);
                if (lRet == -1)
                {
                    strError = "DoNotifyNext()删除通知记录 '" + strQueueRecPath + "' 时失败: " + strError;
                    return -1;
                }
            }

            return 0;
        }
Exemplo n.º 7
0
        public int SubmitLog(out string strErrorText)
        {
            strErrorText = "";
            int nRet;

            ObjEventCollection log = this.Log;
            string strError = "";

            for (int i = 0; i < log.Count; i++)
            {
                ObjEvent objevent = (ObjEvent)log[i];

                if (objevent.Obj.Type == -1)    // 不完整的对象
                    continue;

                if (objevent.Obj.Type == ResTree.RESTYPE_DB)
                    continue;

                // 缺省配置文件,忽略操作
                if (objevent.Oper == ObjEventOper.New
                    || objevent.Oper == ObjEventOper.Change)
                {
                    if (DatabaseObject.IsDefaultFile(objevent.Path) == true)
                        continue;
                }

                if (objevent.Oper == ObjEventOper.New)
                {
                    MemoryStream stream = null;
                    try
                    {
                        if (objevent.Obj.Type == ResTree.RESTYPE_FILE
                            && objevent.Obj.Content != null)
                            stream = new MemoryStream(objevent.Obj.Content);

                        string strPath = objevent.Path;
                        byte[] baOutputTimestamp = null;
                        nRet = NewServerSideObject(strPath,
                            objevent.Obj.Type,
                            stream,
                            objevent.Obj.TimeStamp,
                            out baOutputTimestamp,
                            out strError);
                        if (nRet == -1)
                        {
                            strError = "新建对象 '" + strPath + "' 时发生错误: " + strError;
                            MessageBox.Show(this, strError);
                            strErrorText += strError + "\r\n";
                            // return -1;
                        }
                        else
                        {
                            // 如果创建成功,需要把队列中后面的所有即将操作相同对象的动作修改时间戳
                            // 刷新队列中制定位置以后的、针对某个对象的全部操作的时间戳
                            RefreshTimestamp(
                                i + 1,
                                strPath,
                                baOutputTimestamp);
                        }
                    }
                    finally
                    {
                        if (stream != null)
                            stream.Close();
                    }
                }
                if (objevent.Oper == ObjEventOper.Change)
                {
                    MemoryStream stream = null;
                    try
                    {
                        if (objevent.Obj.Type == ResTree.RESTYPE_FILE)
                            stream = new MemoryStream(objevent.Obj.Content);

                        string strPath = objevent.Path;
                        byte[] baOutputTimestamp = null;
                        nRet = NewServerSideObject(strPath,
                            objevent.Obj.Type,
                            stream,
                            objevent.Obj.TimeStamp,
                            out baOutputTimestamp,
                            out strError);
                        if (nRet == -1)
                        {
                            strError = "修改对象 '" + strPath + "' 时发生错误: " + strError;
                            MessageBox.Show(this, strError);
                            strErrorText += strError + "\r\n";
                        }
                        else
                        {
                            // 如果创建成功,需要把队列中后面的所有即将操作相同对象的动作修改时间戳
                            // 刷新队列中制定位置以后的、针对某个对象的全部操作的时间戳
                            RefreshTimestamp(
                                i + 1,
                                strPath,
                                baOutputTimestamp);
                        }
                    }
                    finally
                    {
                        if (stream != null)
                            stream.Close();
                    }

                }
                else if (objevent.Oper == ObjEventOper.Delete)
                {
                    // TODO: 现在已经有时间戳了,可以不必重试

                    this.channel = Channels.GetChannel(this.ServerUrl);

                    Debug.Assert(channel != null, "Channels.GetChannel() 异常");

                    byte[] baTimestamp = new byte[1];
                    byte[] baOutputTimestamp = null;
                    string strPath = objevent.Path;
                // string strOutputPath = "";
                REDO:
                    // 删除数据库对象
                    long lRet = channel.DoDeleteRes(strPath,
                        baTimestamp,
                        "",
                        out baOutputTimestamp,
                        out strError);
                    if (lRet == -1)
                    {
                        // 时间戳不匹配
                        if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                        {
                            baTimestamp = baOutputTimestamp;
                            goto REDO;
                        }
                        strError = "删除对象 '" + strPath + "' 时发生错误: " + strError;
                        MessageBox.Show(this, strError);
                        strErrorText += strError + "\r\n";
                    }
                }

            }

            log.Clear();

            if (strErrorText == "")
                return 0;
            return -1;
        }
Exemplo n.º 8
0
        // return:
        //		-1	error
        //		0	正常结束
        //		1	希望跳过后来的OnEnd()
        int DoExportFile(
            string[] dbpaths,
            string strOutputFileName,
            ExportFileType exportType,
            Encoding targetEncoding,
            out string strError)
        {
            strError = "";
            int nRet = 0;

            string strDeleteStyle = "";
            if (this.checkBox_export_fastMode.Checked == true)
                strDeleteStyle = "fastmode";

            string strInfo = "";    // 汇总信息,在完成后显示

            FileStream outputfile = null;	// Backup和Xml格式输出都需要这个
            XmlTextWriter writer = null;   // Xml格式输出时需要这个

            bool bAppend = true;

            Debug.Assert(dbpaths != null, "");

            if (dbpaths.Length == 0)
            {
                strError = "尚未指定源库...";
                goto ERROR1;
            }

            if (String.IsNullOrEmpty(strOutputFileName) == false)
            {
                // 探测输出文件是否已经存在
                FileInfo fi = new FileInfo(strOutputFileName);
                bAppend = true;
                if (fi.Exists == true && fi.Length > 0)
                {
                    if (exportType == ExportFileType.BackupFile
                        || exportType == ExportFileType.ISO2709File)
                    {
                        DialogResult result = MessageBox.Show(this,
                            "文件 '" + strOutputFileName + "' 已存在,是否追加?\r\n\r\n--------------------\r\n注:(是)追加  (否)覆盖  (取消)中断处理",
                            "dp2batch",
                            MessageBoxButtons.YesNoCancel,
                            MessageBoxIcon.Question,
                            MessageBoxDefaultButton.Button1);
                        if (result == DialogResult.Yes)
                        {
                            bAppend = true;
                        }
                        if (result == DialogResult.No)
                        {
                            bAppend = false;
                        }
                        if (result == DialogResult.Cancel)
                        {
                            strError = "放弃处理...";
                            goto ERROR1;
                        }
                    }
                    else if (exportType == ExportFileType.XmlFile)
                    {
                        DialogResult result = MessageBox.Show(this,
                            "文件 '" + strOutputFileName + "' 已存在,是否覆盖?\r\n\r\n--------------------\r\n注:(是)覆盖  (否)中断处理",
                            "dp2batch",
                            MessageBoxButtons.YesNo,
                            MessageBoxIcon.Question,
                            MessageBoxDefaultButton.Button2);
                        if (result != DialogResult.Yes)
                        {
                            strError = "放弃处理...";
                            goto ERROR1;
                        }
                    }


                }

                // 打开文件
                if (exportType == ExportFileType.BackupFile
                    || exportType == ExportFileType.ISO2709File)
                {
                    outputfile = File.Open(
                        strOutputFileName,
                        FileMode.OpenOrCreate,	// 原来是Open,后来修改为OpenOrCreate。这样对临时文件被系统管理员手动意外删除(但是xml文件中仍然记载了任务)的情况能够适应。否则会抛出FileNotFoundException异常
                        FileAccess.Write,
                        FileShare.ReadWrite);
                }
                else if (exportType == ExportFileType.XmlFile)
                {
                    outputfile = File.Create(
                        strOutputFileName);

                    writer = new XmlTextWriter(outputfile, Encoding.UTF8);
                    writer.Formatting = Formatting.Indented;
                    writer.Indentation = 4;
                }
            }

            if ((exportType == ExportFileType.BackupFile
                || exportType == ExportFileType.ISO2709File)
                && outputfile != null)
            {
                if (bAppend == true)
                    outputfile.Seek(0, SeekOrigin.End);	// 具有追加的能力
                else
                    outputfile.SetLength(0);
            }

            WriteLog("开始输出");

            try
            {

                // string[] dbpaths = textBox_dbPath.Text.Split(new char[] { ';' });

                for (int f = 0; f < dbpaths.Length; f++)
                {
                    string strOneDbPath = dbpaths[f];

                    ResPath respath = new ResPath(strOneDbPath);

                    channel = this.Channels.GetChannel(respath.Url);

                    string strDbName = respath.Path;
                    if (String.IsNullOrEmpty(strInfo) == false)
                        strInfo += "\r\n";
                    strInfo += "" + strDbName;

                    // 实际处理的首尾号
                    string strRealStartNo = "";
                    string strRealEndNo = "";

                    /*
                    DialogResult result;
                    if (checkBox_export_delete.Checked == true)
                    {
                        result = MessageBox.Show(this,
                            "确实要删除 '" + respath.Path + "' 内指定范围的记录?\r\n\r\n---------\r\n(是)删除 (否)放弃批处理",
                            "dp2batch",
                            MessageBoxButtons.YesNo,
                            MessageBoxIcon.Question,
                            MessageBoxDefaultButton.Button2);
                        if (result != DialogResult.Yes)
                            continue;
                    }
                     * 
                     * */


                    //channel = this.Channels.GetChannel(respath.Url);

                    //string strDbName = respath.Path;

                    // 如果为多库输出
                    if (dbpaths.Length > 0)
                    {
                        // 如果为全选
                        if (this.radioButton_all.Checked == true)
                        {
                            // 恢复为最大范围
                            this.textBox_startNo.Text = "1";
                            this.textBox_endNo.Text = "9999999999";
                        }

                        // 校验起止号
                        if (checkBox_verifyNumber.Checked == true)
                        {
                            nRet = VerifyRange(channel,
                                strDbName,
                                out strError);
                            if (nRet == -1)
                                MessageBox.Show(this, strError);

                            if (nRet == 0)
                            {
                                // 库中无记录
                                AutoCloseMessageBox.Show(this, "数据库 " + strDbName + " 中无记录。");
                                strInfo += "(无记录)";
                                WriteLog("发现数据库 " + strDbName + " 中无记录");
                                continue;
                            }
                        }
                        else
                        {
                            if (this.textBox_startNo.Text == "")
                            {
                                strError = "尚未指定起始号";
                                goto ERROR1;
                            }
                            if (this.textBox_endNo.Text == "")
                            {
                                strError = "尚未指定结束号";
                                goto ERROR1;
                            }
                        }
                    }

                    string strOutputStartNo = "";
                    string strOutputEndNo = "";
                    // 虽然界面不让校验起止号,但是也要校验,为了设置好进度条
                    if (checkBox_verifyNumber.Checked == false)
                    {
                        // 校验起止号
                        // return:
                        //      0   不存在记录
                        //      1   存在记录
                        nRet = VerifyRange(channel,
                            strDbName,
                            this.textBox_startNo.Text,
                            this.textBox_endNo.Text,
                            out strOutputStartNo,
                            out strOutputEndNo,
                            out strError);
                    }

                    //try
                    //{

                    Int64 nStart = 0;
                    Int64 nEnd = 0;
                    Int64 nCur = 0;
                    bool bAsc = true;

                    bAsc = GetDirection(
                        this.textBox_startNo.Text,
                        this.textBox_endNo.Text,
                        out nStart,
                        out nEnd);

                    // 探测到的号码
                    long nOutputEnd = 0;
                    long nOutputStart = 0;
                    if (checkBox_verifyNumber.Checked == false)
                    {
                        GetDirection(
                            strOutputStartNo,
                            strOutputEndNo,
                            out nOutputStart,
                            out nOutputEnd);
                    }

                    // 设置进度条范围
                    if (checkBox_verifyNumber.Checked == true)
                    {

                        Int64 nMax = nEnd - nStart;
                        if (nMax < 0)
                            nMax *= -1;
                        nMax++;

                        /*
                        ProgressRatio = nMax / 10000;
                        if (ProgressRatio < 1.0)
                            ProgressRatio = 1.0;

                        progressBar_main.Minimum = 0;
                        progressBar_main.Maximum = (int)(nMax / ProgressRatio);
                        progressBar_main.Value = 0;
                         * */
                        stop.SetProgressRange(0, nMax);
                    }
                    else
                    {
                        Int64 nMax = nOutputEnd - nOutputStart;
                        if (nMax < 0)
                            nMax *= -1;
                        nMax++;
                        stop.SetProgressRange(0, nMax);
                    }


                    bool bFirst = true;	// 是否为第一次取记录

                    string strID = this.textBox_startNo.Text;

                    stop.OnStop += new StopEventHandler(this.DoStop);
                    stop.Initial("正在导出数据");
                    stop.BeginLoop();

                    EnableControls(false);

                    if (exportType == ExportFileType.XmlFile
                        && writer != null)
                    {
                        writer.WriteStartDocument();
                        writer.WriteStartElement("dprms", "collection", DpNs.dprms);
                        //writer.WriteStartElement("collection");
                        //writer.WriteAttributeString("xmlns:marc",
                        //	"http://www.loc.gov/MARC21/slim");

                    }

                    WriteLog("开始输出数据库 '" + strDbName + "' 内的数据记录");

                    m_nRecordCount = 0;
                    // 循环
                    for (; ; )
                    {
                        Application.DoEvents();	// 出让界面控制权

                        if (stop.State != 0)
                        {
                            WriteLog("打开对话框 '确实要中断当前批处理操作?'");
                            DialogResult result = MessageBox.Show(this,
                                "确实要中断当前批处理操作?",
                                "dp2batch",
                                MessageBoxButtons.YesNo,
                                MessageBoxIcon.Question,
                                MessageBoxDefaultButton.Button2);
                            WriteLog("关闭对话框 '确实要中断当前批处理操作?'");
                            if (result == DialogResult.Yes)
                            {
                                strError = "用户中断";
                                goto ERROR1;
                            }
                            else
                            {
                                stop.Continue();
                            }
                        }

                        string strDirectionComment = "";
                        string strStyle = "";
                        if (outputfile != null)
                            strStyle = "data,content,timestamp,outputpath";
                        else
                            strStyle = "timestamp,outputpath";	// 优化

                        if (bFirst == true)
                        {
                            strStyle += "";
                        }
                        else
                        {
                            if (bAsc == true)
                            {
                                strStyle += ",next";
                                strDirectionComment = "的后一条记录";
                            }
                            else
                            {
                                strStyle += ",prev";
                                strDirectionComment = "的前一条记录";
                            }
                        }


                        string strPath = strDbName + "/" + strID;
                        string strXmlBody = "";
                        string strMetaData = "";
                        byte[] baOutputTimeStamp = null;
                        string strOutputPath = "";

                        bool bFoundRecord = false;

                        bool bNeedRetry = true;

                    REDO_GETRES:
                        // 获得资源
                        // return:
                        //		-1	出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。
                        //		0	成功
                        long lRet = channel.GetRes(strPath,
                            strStyle,
                            out strXmlBody,
                            out strMetaData,
                            out baOutputTimeStamp,
                            out strOutputPath,
                            out strError);


                        if (lRet == -1)
                        {
                            if (channel.ErrorCode == ChannelErrorCode.NotFound)
                            {
                                if (bFirst == true)
                                {
                                    if (checkBox_forceLoop.Checked == true)
                                    {
                                        string strText = "记录 " + strID + strDirectionComment + " 不存在。\r\n\r\n按 确认 继续。";
                                        WriteLog("打开对话框 '" + strText.Replace("\r\n", "\\n") + "'");
                                        AutoCloseMessageBox.Show(this, strText);
                                        WriteLog("关闭对话框 '" + strText.Replace("\r\n", "\\n") + "'");

                                        bFirst = false;
                                        goto CONTINUE;
                                    }
                                    else
                                    {
                                        // 如果不要强制循环,此时也不能结束,否则会让用户以为数据库里面根本没有数据
                                        string strText = "您为数据库 " + strDbName + " 指定的首记录 " + strID + strDirectionComment + " 不存在。\r\n\r\n(注:为避免出现此提示,可在操作前勾选“校准首尾ID”)\r\n\r\n按 确认 继续向后找...";
                                        WriteLog("打开对话框 '" + strText.Replace("\r\n", "\\n") + "'");
                                        AutoCloseMessageBox.Show(this, strText);
                                        WriteLog("关闭对话框 '" + strText.Replace("\r\n", "\\n") + "'");

                                        bFirst = false;
                                        goto CONTINUE;
                                    }
                                }
                                else
                                {
                                    Debug.Assert(bFirst == false, "");

                                    if (bFirst == true)
                                    {
                                        strError = "记录 " + strID + strDirectionComment + " 不存在。处理结束。";
                                    }
                                    else
                                    {
                                        if (bAsc == true)
                                            strError = "记录 " + strID + " 是最末一条记录。处理结束。";
                                        else
                                            strError = "记录 " + strID + " 是最前一条记录。处理结束。";
                                    }

                                    if (dbpaths.Length > 1)
                                        break;  // 多库情况,继续其它库循环
                                    else
                                    {
                                        bNeedRetry = false; // 单库情况,也没有必要出现重试对话框

                                        WriteLog("打开对话框 '" + strError.Replace("\r\n", "\\n") + "'");
                                        MessageBox.Show(this, strError);
                                        WriteLog("关闭对话框 '" + strError.Replace("\r\n", "\\n") + "'");
                                        break;
                                    }
                                }

                            }
                            else if (channel.ErrorCode == ChannelErrorCode.EmptyRecord)
                            {
                                bFirst = false;
                                bFoundRecord = false;
                                // 把id解析出来
                                strID = ResPath.GetRecordId(strOutputPath);
                                goto CONTINUE;

                            }

                            // 允许重试
                            if (bNeedRetry == true)
                            {
                                string strText = "获取记录 '" + strPath + "' (style='" + strStyle + "')时出现错误: " + strError + "\r\n\r\n重试,还是中断当前批处理操作?\r\n(Retry 重试;Cancel 中断批处理)";
                                WriteLog("打开对话框 '" + strText.Replace("\r\n", "\\n") + "'");
                                DialogResult redo_result = MessageBox.Show(this,
                                    strText,
                                    "dp2batch",
                                    MessageBoxButtons.RetryCancel,
                                    MessageBoxIcon.Question,
                                    MessageBoxDefaultButton.Button1);
                                WriteLog("关闭对话框 '" + strText.Replace("\r\n", "\\n") + "'");
                                if (redo_result == DialogResult.Cancel)
                                    goto ERROR1;
                                goto
                                    REDO_GETRES;
                            }
                            else
                            {
                                goto ERROR1;
                            }
                        }

                        // 2008/11/9 
                        if (String.IsNullOrEmpty(strXmlBody) == true)
                        {
                            bFirst = false;
                            bFoundRecord = false;
                            // 把id解析出来
                            strID = ResPath.GetRecordId(strOutputPath);
                            goto CONTINUE;
                        }

                        bFirst = false;

                        bFoundRecord = true;

                        // 把id解析出来
                        strID = ResPath.GetRecordId(strOutputPath);
                        stop.SetMessage("已导出记录 " + strOutputPath + "  " + m_nRecordCount.ToString());

                        if (String.IsNullOrEmpty(strRealStartNo) == true)
                        {
                            strRealStartNo = strID;
                        }

                        strRealEndNo = strID;

                    CONTINUE:

                        // 是否超过循环范围
                        try
                        {
                            nCur = Convert.ToInt64(strID);
                        }
                        catch
                        {
                            // ???
                            nCur = 0;
                        }

                        if (checkBox_verifyNumber.Checked == false)
                        {
                            // 如果当前记录号码突破预计的头部和尾部
                            if (nCur > nOutputEnd
                                || nCur < nOutputStart)
                            {
                                if (nCur > nOutputEnd)
                                    nOutputEnd = nCur;

                                if (nCur < nOutputStart)
                                    nOutputStart = nCur;

                                // 重新计算和设置进度条
                                long nMax = nOutputEnd - nOutputStart;
                                if (nMax < 0)
                                    nMax *= -1;
                                nMax++;

                                stop.SetProgressRange(0, nMax);
                            }
                        }

                        if (bAsc == true && nCur > nEnd)
                            break;
                        if (bAsc == false && nCur < nEnd)
                            break;

                        string strMarc = "";

                        // 将Xml转换为MARC
                        if (exportType == ExportFileType.ISO2709File
                            && bFoundRecord == true)    // 2008/11/13 
                        {
                            nRet = GetMarc(strXmlBody,
                                out strMarc,
                                out strError);
                            if (nRet == -1)
                            {
                                strError = "记录 " + strOutputPath + " 在将XML格式转换为MARC时出错: " + strError;
                                goto ERROR1;
                            }
                        }

                        if (this.MarcFilter != null)
                        {
                            // 触发filter中的Record相关动作
                            // TODO: 有可能strMarc为空哟,需要测试一下
                            nRet = MarcFilter.DoRecord(
                                null,
                                strMarc,
                                m_nRecordCount,
                                out strError);
                            if (nRet == -1)
                                goto ERROR1;
                        }

                        // 触发Script的Outputing()代码
                        if (bFoundRecord == true && this.AssemblyMain != null)
                        {
                            // 这些变量要先初始化,因为filter代码可能用到这些Batch成员.
                            batchObj.XmlRecord = strXmlBody;

                            batchObj.MarcSyntax = this.CurMarcSyntax;

                            batchObj.MarcRecord = strMarc;	// MARC记录体
                            batchObj.MarcRecordChanged = false;	// 为本轮Script运行准备初始状态

                            batchObj.SearchPanel.ServerUrl = channel.Url;
                            batchObj.ServerUrl = channel.Url;
                            batchObj.RecPath = strOutputPath;	// 记录路径
                            batchObj.RecIndex = m_nRecordCount;	// 当前记录在一批中的序号
                            batchObj.TimeStamp = baOutputTimeStamp;


                            BatchEventArgs args = new BatchEventArgs();

                            batchObj.Outputing(this, args);
                            /*
                            if (args.Continue == ContinueType.SkipMiddle)
                                goto CONTINUEDBS;
                            if (args.Continue == ContinueType.SkipBeginMiddle)
                                goto CONTINUEDBS;
                            */
                            if (args.Continue == ContinueType.SkipAll)
                                goto CONTINUEDBS;

                            // 观察用于输出的MARC记录是否被改变
                            if (batchObj.MarcRecordChanged == true)
                                strMarc = batchObj.MarcRecord;

                            // 观察XML记录是否被改变
                            if (batchObj.XmlRecordChanged == true)
                                strXmlBody = batchObj.XmlRecord;

                        }


                        if (bFoundRecord == true
                            && outputfile != null)
                        {
                            if (exportType == ExportFileType.BackupFile)
                            {
                                // 写磁盘
                                nRet = WriteRecordToBackupFile(
                                    outputfile,
                                    strDbName,
                                    strID,
                                    strMetaData,
                                    strXmlBody,
                                    baOutputTimeStamp,
                                    out strError);
                                if (nRet == -1)
                                {
                                    // 询问是否继续
                                    goto ERROR1;
                                }
                            }
                            else if (exportType == ExportFileType.ISO2709File)
                            {
                                // 写磁盘
                                nRet = WriteRecordToISO2709File(
                                    outputfile,
                                    strDbName,
                                    strID,
                                    strMarc,
                                    baOutputTimeStamp,
                                    targetEncoding,
                                    this.OutputCrLf,
                                    this.AddG01,
                                    this.Remove998,
                                    out strError);
                                if (nRet == -1)
                                {
                                    // 询问是否继续
                                    goto ERROR1;
                                }
                            }
                            else if (exportType == ExportFileType.XmlFile)
                            {
                                XmlDocument dom = new XmlDocument();

                                try
                                {
                                    dom.LoadXml(strXmlBody);

                                    ResPath respathtemp = new ResPath();
                                    respathtemp.Url = channel.Url;
                                    respathtemp.Path = strOutputPath;


                                    // DomUtil.SetAttr(dom.DocumentElement, "xmlns:dprms", DpNs.dprms);
                                    // 给根元素设置几个参数
                                    DomUtil.SetAttr(dom.DocumentElement, "path", DpNs.dprms, respathtemp.FullPath);
                                    DomUtil.SetAttr(dom.DocumentElement, "timestamp", DpNs.dprms, ByteArray.GetHexTimeStampString(baOutputTimeStamp));

                                    // DomUtil.SetAttr(dom.DocumentElement, "xmlns:marc", null);
                                    dom.DocumentElement.WriteTo(writer);
                                }
                                catch (Exception ex)
                                {
                                    strError = ExceptionUtil.GetAutoText(ex);
                                    // 询问是否继续
                                    goto ERROR1;
                                }

                            }
                        }

                        // 删除
                        if (checkBox_export_delete.Checked == true)
                        {

                            byte[] baOutputTimeStamp1 = null;
                            strPath = strOutputPath;	// 得到实际的路径
                            lRet = channel.DoDeleteRes(
                                strPath,
                                baOutputTimeStamp,
                                strDeleteStyle,
                                out baOutputTimeStamp1,
                                out strError);
                            if (lRet == -1)
                            {
                                // 询问是否继续
                                goto ERROR1;
                            }
                            stop.SetMessage("已删除记录" + strPath + "  " + m_nRecordCount.ToString());
                        }

                        if (bFoundRecord == true)
                            m_nRecordCount++;


                        if (bAsc == true)
                        {
                            //progressBar_main.Value = (int)((nCur - nStart + 1) / ProgressRatio);
                            stop.SetProgressValue(nCur - nStart + 1);
                        }
                        else
                        {
                            // ?
                            // progressBar_main.Value = (int)((nStart - nCur + 1) / ProgressRatio);
                            stop.SetProgressValue(nStart - nCur + 1);
                        }


                        // 对已经作过的进行判断
                        if (bAsc == true && nCur >= nEnd)
                            break;
                        if (bAsc == false && nCur <= nEnd)
                            break;


                    } // end of for one database

                    stop.EndLoop();
                    stop.OnStop -= new StopEventHandler(this.DoStop);
                    stop.Initial("");

                    EnableControls(true);

                //}

            CONTINUEDBS:
                    strInfo += " : " + m_nRecordCount.ToString() + "条 (ID " + strRealStartNo + "-" + strRealEndNo + ")";

                }   // end of dbpaths loop


            }   // end of try
            finally
            {
                if (writer != null)
                {
                    writer.WriteEndElement();
                    writer.WriteEndDocument();
                    writer.Close();
                    writer = null;
                }

                if (outputfile != null)
                {
                    outputfile.Close();
                    outputfile = null;
                }
            }

            // END1:
            channel = null;

            if (checkBox_export_delete.Checked == true)
                strError = "数据导出和删除完成。\r\n---\r\n" + strInfo;
            else
                strError = "数据导出完成。\r\n---\r\n" + strInfo;

            WriteLog("结束输出");

            return 0;
        ERROR1:
            stop.EndLoop();
            stop.OnStop -= new StopEventHandler(this.DoStop);
            stop.Initial("");

            EnableControls(true);
            channel = null;
            return -1;
        }
Exemplo n.º 9
0
        // 删除期记录的操作
        int DoIssueOperDelete(
            SessionInfo sessioninfo,
            RmsChannel channel,
            IssueInfo info,
            string strIssueDbName,
            string strParentID,
            string strOldPublishTime,
            string strNewPublishTime,   // TODO: 本参数是否可以废除?
            XmlDocument domOldRec,
            ref XmlDocument domOperLog,
            ref List<IssueInfo> ErrorInfos)
        {
            int nRedoCount = 0;
            IssueInfo error = null;
            int nRet = 0;
            long lRet = 0;
            string strError = "";

            // 如果newrecpath为空但是oldrecpath有值,就用oldrecpath的值
            // 2007/10/23
            if (String.IsNullOrEmpty(info.NewRecPath) == true)
            {
                if (String.IsNullOrEmpty(info.OldRecPath) == false)
                    info.NewRecPath = info.OldRecPath;
            }


            // 如果记录路径为空, 则先获得记录路径
            if (String.IsNullOrEmpty(info.NewRecPath) == true)
            {
                List<string> aPath = null;

                if (String.IsNullOrEmpty(strOldPublishTime) == true)
                {
                    strError = "info.OldRecord中的<publishTime>元素中的出版时间,和info.RecPath参数值,不能同时为空。";
                    goto ERROR1;
                }

                // 本函数只负责查重, 并不获得记录体
                // return:
                //      -1  error
                //      其他    命中记录条数(不超过nMax规定的极限)
                nRet = this.SearchIssueRecDup(
                    sessioninfo.Channels,
                    strIssueDbName,
                    strParentID,
                    strOldPublishTime,
                    100,
                    out aPath,
                    out strError);
                if (nRet == -1)
                {
                    strError = "删除操作中出版时间查重阶段发生错误:" + strError;
                    goto ERROR1;
                }


                if (nRet == 0)
                {
                    error = new IssueInfo(info);
                    error.ErrorInfo = "父记录ID为 '"+strParentID+"', + 出版时间为 '" + strOldPublishTime + "' 的期记录已不存在";
                    error.ErrorCode = ErrorCodeValue.NotFound;
                    ErrorInfos.Add(error);
                    return -1;
                }


                if (nRet > 1)
                {
                    string[] pathlist = new string[aPath.Count];
                    aPath.CopyTo(pathlist);

                    // 在删除操作中,遇到重复的是很平常的事情。只要
                    // info.OldRecPath能够清晰地指出要删除的那一条,就可以执行删除
                    if (String.IsNullOrEmpty(info.OldRecPath) == false)
                    {
                        if (aPath.IndexOf(info.OldRecPath) == -1)
                        {
                            strError = "出版时间 '" + strOldPublishTime + "' 已经被下列多条期记录使用了: " + String.Join(",", pathlist) + "',但并不包括info.OldRecPath所指的路径 '" + info.OldRecPath + "'。";
                            goto ERROR1;
                        }
                        info.NewRecPath = info.OldRecPath;
                    }
                    else
                    {

                        strError = "出版时间 '" + strOldPublishTime + "' 已经被下列多条期记录使用了: " + String.Join(",", pathlist) + "',这是一个严重的系统故障,请尽快通知系统管理员处理。";
                        goto ERROR1;
                    }
                }
                else
                {
                    Debug.Assert(nRet == 1, "");

                    info.NewRecPath = aPath[0];
                }

                ///

                /*

                if (nRet > 1)
                {
                    string[] pathlist = new string[aPath.Count];
                    aPath.CopyTo(pathlist);

                    strError = "出版时间 '" + strOldPublishTime + "' 已经被下列多条期记录使用了: " + String.Join(",", pathlist) + "',这是一个严重的系统故障,请尽快通知系统管理员处理。";
                    goto ERROR1;
                }

                info.NewRecPath = aPath[0];
                 * */
            }

            Debug.Assert(String.IsNullOrEmpty(info.NewRecPath) == false, "");
            // Debug.Assert(strEntityDbName != "", "");

            byte[] exist_timestamp = null;
            string strOutputPath = "";
            string strMetaData = "";
            string strExistingXml = "";

        REDOLOAD:

            // 先读出数据库中此位置的已有记录
            lRet = channel.GetRes(info.NewRecPath,
                out strExistingXml,
                out strMetaData,
                out exist_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                if (channel.ErrorCode == ChannelErrorCode.NotFound)
                {
                    error = new IssueInfo(info);
                    error.ErrorInfo = "出版时间为 '" + strOldPublishTime + "' 的期记录 '" + info.NewRecPath + "' 已不存在";
                    error.ErrorCode = channel.OriginErrorCode;
                    ErrorInfos.Add(error);
                    return -1;
                }
                else
                {
                    error = new IssueInfo(info);
                    error.ErrorInfo = "删除操作发生错误, 在读入原有记录 '" + info.NewRecPath + "' 阶段:" + strError;
                    error.ErrorCode = channel.OriginErrorCode;
                    ErrorInfos.Add(error);
                    return -1;
                }
            }

            // 把记录装入DOM
            XmlDocument domExist = new XmlDocument();

            try
            {
                domExist.LoadXml(strExistingXml);
            }
            catch (Exception ex)
            {
                strError = "strExistXml装载进入DOM时发生错误: " + ex.Message;
                goto ERROR1;
            }

            // 观察已经存在的记录中,出版时间是否和strOldPublishTime一致
            if (String.IsNullOrEmpty(strOldPublishTime) == false)
            {
                string strExistingPublishTime = DomUtil.GetElementText(domExist.DocumentElement,
                    "publishTime");
                if (strExistingPublishTime != strOldPublishTime)
                {
                    strError = "路径为 '" + info.NewRecPath + "' 的期记录中<publishTime>元素中的出版时间 '" + strExistingPublishTime + "' 和strOldXml中<publishTime>元素中的出版时间 '" + strOldPublishTime + "' 不一致。拒绝删除(如果允许删除,则会造成不经意删除了别的期记录的危险)。";
                    goto ERROR1;
                }
            }

            /*
            // 观察已经存在的记录是否有流通信息
            if (IsIssueHasCirculationInfo(domExist) == true)
            {
                strError = "拟删除的期记录 '" + info.NewRecPath + "' 中包含有流通信息,不能删除。";
                goto ERROR1;
            }*/

            // 比较时间戳
            // 观察时间戳是否发生变化
            nRet = ByteArray.Compare(info.OldTimestamp, exist_timestamp);
            if (nRet != 0)
            {
                // 如果前端给出了旧记录,就有和库中记录进行比较的基础
                if (String.IsNullOrEmpty(info.OldRecord) == false)
                {
                    // 比较两个记录, 看看和期要害信息有关的字段是否发生了变化
                    // return:
                    //      0   没有变化
                    //      1   有变化
                    nRet = IsIssueInfoChanged(domExist,
                        domOldRec);
                    if (nRet == 1)
                    {

                        error = new IssueInfo(info);
                        error.NewTimestamp = exist_timestamp;   // 让前端知道库中记录实际上发生过变化
                        error.ErrorInfo = "数据库中即将删除的期记录已经发生了变化,请重新装载、仔细核对后再行删除。";
                        error.ErrorCode = ErrorCodeValue.TimestampMismatch;
                        ErrorInfos.Add(error);
                        return -1;
                    }
                }

                info.OldTimestamp = exist_timestamp;
                info.NewTimestamp = exist_timestamp;
            }

            byte[] output_timestamp = null;

            lRet = channel.DoDeleteRes(info.NewRecPath,
                info.OldTimestamp,
                out output_timestamp,
                out strError);
            if (lRet == -1)
            {
                if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                {
                    if (nRedoCount > 10)
                    {
                        strError = "反复删除均遇到时间戳冲突, 超过10次重试仍然失败";
                        goto ERROR1;
                    }
                    // 发现时间戳不匹配
                    // 重复进行提取已存在记录\比较的过程
                    nRedoCount++;
                    goto REDOLOAD;
                }

                error = new IssueInfo(info);
                error.NewTimestamp = output_timestamp;
                error.ErrorInfo = "删除操作发生错误:" + strError;
                error.ErrorCode = channel.OriginErrorCode;
                ErrorInfos.Add(error);
                return -1;
            }
            else
            {
                // 成功
                DomUtil.SetElementText(domOperLog.DocumentElement, "action", "delete");

                // 不创建<record>元素

                XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement,
                    "oldRecord", strExistingXml);
                DomUtil.SetAttr(node, "recPath", info.NewRecPath);


                // 如果删除成功,则不必要在数组中返回表示成功的信息元素了
            }

            return 0;
        ERROR1:
            error = new IssueInfo(info);
            error.ErrorInfo = strError;
            error.ErrorCode = ErrorCodeValue.CommonError;
            ErrorInfos.Add(error);
            return -1;
        }
Exemplo n.º 10
0
        // 删除读者记录的操作
        // return:
        //      -2  记录中有流通信息,不能删除
        //      -1  出错
        //      0   记录本来就不存在
        //      1   记录成功删除
        int DoReaderOperDelete(
            string strCurrentLibraryCode,
            string[] element_names,
            SessionInfo sessioninfo,
            bool bForce,
            RmsChannel channel,
            string strRecPath,
            string strOldXml,
            byte[] baOldTimestamp,
            string strOldBarcode,
            // string strNewBarcode,
            XmlDocument domOldRec,
            ref string strExistingXml,
            ref byte[] baNewTimestamp,
            ref XmlDocument domOperLog,
            ref DigitalPlatform.rms.Client.rmsws_localhost.ErrorCodeValue kernel_errorcode,
            out string strError)
        {
            strError = "";

            int nRedoCount = 0;
            int nRet = 0;
            long lRet = 0;

            // 如果记录路径为空, 则先获得记录路径
            if (String.IsNullOrEmpty(strRecPath) == true)
            {
                List<string> aPath = null;

                if (String.IsNullOrEmpty(strOldBarcode) == true)
                {
                    strError = "strOldXml中的<barcode>元素中的证条码号,和strRecPath参数值,不能同时为空。";
                    goto ERROR1;
                }

                // 本函数只负责查重, 并不获得记录体
                // return:
                //      -1  error
                //      其他    命中记录条数(不超过nMax规定的极限)
                nRet = this.SearchReaderRecDup(
                    // sessioninfo.Channels,
                    channel,
                    strOldBarcode,
                    100,
                    out aPath,
                    out strError);
                if (nRet == -1)
                    goto ERROR1;

                if (nRet == 0)
                {
                    strError = "证条码号为 '" + strOldBarcode + "' 的读者记录已不存在";
                    kernel_errorcode = ErrorCodeValue.NotFound;
                    // goto ERROR1;
                    return 0;   // 2009/7/17 changed
                }


                if (nRet > 1)
                {
                    /*
                    string[] pathlist = new string[aPath.Count];
                    aPath.CopyTo(pathlist);
                     * */

                    // 2007/11/22 
                    // 在删除操作中,遇到重复的是很平常的事情。只要
                    // strRecPath能够清晰地指出要删除的那一条,就可以执行删除
                    if (String.IsNullOrEmpty(strRecPath) == false)
                    {
                        if (aPath.IndexOf(strRecPath) == -1)
                        {
                            strError = "证条码号 '" + strOldBarcode + "' 已经被下列多条读者记录使用了: " + StringUtil.MakePathList(aPath)/*String.Join(",", pathlist)*/ + "',但并不包括strRecPath所指的路径 '" + strRecPath + "'。删除操作失败。";
                            goto ERROR1;
                        }
                    }
                    else
                    {
                        strError = "证条码号 '" + strOldBarcode + "' 已经被下列多条读者记录使用了: " + StringUtil.MakePathList(aPath)/*String.Join(",", pathlist)*/ + "',在未指定记录路径的情况下,无法定位和删除。";
                        goto ERROR1;
                    }
                }
                else
                {

                    strRecPath = aPath[0];
                    // strReaderDbName = ResPath.GetDbName(strRecPath);
                }
            }

            // 删除动作,API 的 strRecPath 参数可能为空,所以这里要单独检查一次
            if (this.TestMode == true || sessioninfo.TestMode == true)
            {
                // 检查评估模式
                // return:
                //      -1  检查过程出错
                //      0   可以通过
                //      1   不允许通过
                nRet = CheckTestModePath(strRecPath,
                    out strError);
                if (nRet != 0)
                {
                    strError = "删除读者记录的操作被拒绝: " + strError;
                    goto ERROR1;
                }
            }

            // Debug.Assert(strReaderDbName != "", "");

            byte[] exist_timestamp = null;
            string strOutputPath = "";
            string strMetaData = "";

        REDOLOAD:


            // 先读出数据库中此位置的已有记录
            lRet = channel.GetRes(strRecPath,
                out strExistingXml,
                out strMetaData,
                out exist_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                if (channel.ErrorCode == ChannelErrorCode.NotFound)
                {
                    kernel_errorcode = channel.OriginErrorCode;
                    goto ERROR1;
                }
                else
                {
                    strError = "删除操作发生错误, 在读入原有记录阶段:" + strError;
                    kernel_errorcode = channel.OriginErrorCode;
                    goto ERROR1;
                }
            }

            // 把记录装入DOM
            XmlDocument domExist = new XmlDocument();

            try
            {
                domExist.LoadXml(strExistingXml);
            }
            catch (Exception ex)
            {
                strError = "strExistXml装载进入DOM时发生错误: " + ex.Message;
                goto ERROR1;
            }

            string strExistingBarcode = DomUtil.GetElementText(domExist.DocumentElement, "barcode");


            // 观察已经存在的记录中,证条码号是否和strOldBarcode一致
            if (String.IsNullOrEmpty(strOldBarcode) == false)
            {
                if (strExistingBarcode != strOldBarcode)
                {
                    strError = "路径为 '" + strRecPath + "' 的读者记录中<barcode>元素中的证条码号 '" + strExistingBarcode + "' 和strOldXml中<barcode>元素中的证条码号 '" + strOldBarcode + "' 不一致。拒绝删除(如果允许删除,则会造成不经意删除了别的读者记录的危险)。";
                    goto ERROR1;
                }
            }

            // 清除 LoginCache
            // this.LoginCache.Remove(strExistingBarcode);
            this.ClearLoginCache(strExistingBarcode);

            // 观察已经存在的记录是否有流通信息
            string strDetailInfo = "";
            bool bHasCirculationInfo = IsReaderHasCirculationInfo(domExist,
                out strDetailInfo);

            if (bForce == false)
            {
                if (bHasCirculationInfo == true)
                {
                    strError = "删除操作被拒绝。因拟删除的读者记录 '" + strRecPath + "' 中包含有 " + strDetailInfo + "";
                    goto ERROR2;
                }
            }

            // 比较时间戳
            // 观察时间戳是否发生变化
            nRet = ByteArray.Compare(baOldTimestamp, exist_timestamp);
            if (nRet != 0)
            {
                // 2008/5/29 
                if (bForce == true)
                {
                    strError = "数据库中即将删除的读者记录已经发生了变化,请重新装载、仔细核对后再行删除。";
                    kernel_errorcode = ErrorCodeValue.TimestampMismatch;
                    baNewTimestamp = exist_timestamp;   // 让前端知道库中记录实际上发生过变化
                    goto ERROR1;
                }

                // 是否报错?
                // 功能做的精细一点,需要比较strOldXml和strExistingXml中要害字段是否被改变了,如果没有改变,是不必报错的

                // 如果前端给出了旧记录,就有和库中记录进行比较的基础
                if (String.IsNullOrEmpty(strOldXml) == false)
                {
                    // 比较两个记录, 看看和读者静态信息有关的字段是否发生了变化
                    // return:
                    //      0   没有变化
                    //      1   有变化
                    nRet = IsReaderInfoChanged(
                        element_names,
                        domExist,
                        domOldRec);
                    if (nRet == 1)
                    {

                        strError = "数据库中即将删除的读者记录已经发生了变化,请重新装载、仔细核对后再行删除。";
                        kernel_errorcode = ErrorCodeValue.TimestampMismatch;

                        baNewTimestamp = exist_timestamp;   // 让前端知道库中记录实际上发生过变化
                        goto ERROR1;
                    }
                }

                baOldTimestamp = exist_timestamp;
                baNewTimestamp = exist_timestamp;   // 让前端知道库中记录实际上发生过变化
            }

            string strLibraryCode = "";
            // 观察一个读者记录路径,看看是不是在当前用户管辖的读者库范围内?
            if (this.IsCurrentChangeableReaderPath(strRecPath,
                strCurrentLibraryCode,
                out strLibraryCode) == false)
            {
                strError = "读者记录路径 '" + strRecPath + "' 的读者库不在当前用户管辖范围内";
                goto ERROR1;
            }

            byte[] output_timestamp = null;

            Debug.Assert(strRecPath != "", "");

            lRet = channel.DoDeleteRes(strRecPath,
                baOldTimestamp,
                out output_timestamp,
                out strError);
            if (lRet == -1)
            {
                // 2009/7/17 
                if (channel.ErrorCode == ChannelErrorCode.NotFound)
                {
                    strError = "证条码号为 '" + strOldBarcode + "' 的读者记录(在删除的时候发现)已不存在";
                    kernel_errorcode = ErrorCodeValue.NotFound;
                    return 0;
                }

                if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                {
                    if (nRedoCount > 10)
                    {
                        strError = "反复删除均遇到时间戳冲突, 超过10次重试仍然失败";
                        baNewTimestamp = output_timestamp;
                        kernel_errorcode = channel.OriginErrorCode;
                        goto ERROR1;
                    }
                    // 发现时间戳不匹配
                    // 重复进行提取已存在记录\比较的过程
                    nRedoCount++;
                    goto REDOLOAD;
                }


                baNewTimestamp = output_timestamp;
                strError = "删除操作发生错误:" + strError;
                kernel_errorcode = channel.OriginErrorCode;
                goto ERROR1;
            }
            else
            {
                // 成功
                DomUtil.SetElementText(domOperLog.DocumentElement,
    "libraryCode",
    strLibraryCode);    // 读者所在的馆代码

                DomUtil.SetElementText(domOperLog.DocumentElement, "action", "delete");

                // 不创建<record>元素

                {
                    XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement,
                        "oldRecord", strExistingXml);
                    DomUtil.SetAttr(node, "recPath", strRecPath);
                }

                // 2014/11/17
                if (bForce == true)
                {
                    XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement,
        "style", "force");
                    if (string.IsNullOrEmpty(strDetailInfo) == false
                        && bHasCirculationInfo == true)
                        DomUtil.SetAttr(node, "description", strDetailInfo);
                }

                // 如果删除成功,则不必要在数组中返回表示成功的信息元素了

                /// 
                if (this.Statis != null)
                    this.Statis.IncreaseEntryValue(strLibraryCode,
    "修改读者信息",
    "删除记录数",
    1);
            }

            return 1;
        ERROR1:
            kernel_errorcode = ErrorCodeValue.CommonError;
            domOperLog = null;  // 表示不必写入日志
            return -1;
        ERROR2:
            kernel_errorcode = ErrorCodeValue.CommonError;
            domOperLog = null;  // 表示不必写入日志
            return -2;
        }
Exemplo n.º 11
0
        // 结算一个交费记录
        // parameters:
        //      strLibraryCodeList  当前操作者管辖的图书馆代码
        //      bCreateOperLog  是否创建日志
        //      strOperTime 结算的操作时间
        //      strOperator 结算的操作者
        // return:
        //      -2  致命出错,不宜再继续循环调用本函数
        //      -1  一般出错,可以继续循环调用本函数
        //      0   正常
        int SettlementOneRecord(
            string strLibraryCodeList,
            bool bCreateOperLog,
            RmsChannel channel,
            string strAction,
            string strAmercedRecPath,
            string strOperTime,
            string strOperator,
            string strClientAddress,
            out string strError)
        {
            strError = "";

            string strMetaData = "";
            byte[] amerced_timestamp = null;
            string strOutputPath = "";
            string strAmercedXml = "";

            // 准备日志DOM
            XmlDocument domOperLog = null;

            if (bCreateOperLog == true)
            {

            }

            int nRedoCount = 0;
        REDO:

            long lRet = channel.GetRes(strAmercedRecPath,
                out strAmercedXml,
                out strMetaData,
                out amerced_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                strError = "获取违约金记录 '" + strAmercedRecPath + "' 时出错: " + strError;
                return -1;
            }

            XmlDocument amerced_dom = null;
            int nRet = LibraryApplication.LoadToDom(strAmercedXml,
                out amerced_dom,
                out strError);
            if (nRet == -1)
            {
                strError = "装载违约金记录进入XML DOM时发生错误: " + strError;
                return -1;
            }

            string strLibraryCode = DomUtil.GetElementText(amerced_dom.DocumentElement, "libraryCode");
            if (SessionInfo.IsGlobalUser(strLibraryCodeList) == false)
            {
                if (StringUtil.IsInList(strLibraryCode, strLibraryCodeList) == false)
                {
                    strError = "当前用户未能管辖违约金记录 '" + strAmercedRecPath + "' 所在的馆代码 '" + strLibraryCode + "'";
                    return -1;
                }
            }

            if (bCreateOperLog == true)
            {
                domOperLog = new XmlDocument();
                domOperLog.LoadXml("<root />");

                // 2012/10/2
                // 相关读者所在的馆代码
                DomUtil.SetElementText(domOperLog.DocumentElement,
                    "libraryCode", strLibraryCode);

                DomUtil.SetElementText(domOperLog.DocumentElement, "operation",
                    "settlement");
                DomUtil.SetElementText(domOperLog.DocumentElement, "action",
                    strAction);


                // 在日志中记忆 id
                string strID = DomUtil.GetElementText(amerced_dom.DocumentElement,
                    "id");
                DomUtil.SetElementText(domOperLog.DocumentElement,
                    "id", strID);
            }

            string strOldState = DomUtil.GetElementText(amerced_dom.DocumentElement,
                "state");

            if (strAction == "settlement")
            {
                if (strOldState != "amerced")
                {
                    strError = "结算操作前,记录状态必须为amerced。(但发现为'" + strOldState + "')";
                    return -1;
                }
                if (strOldState == "settlemented")
                {
                    strError = "结算操作前,记录状态已经为settlemented";
                    return -1;
                }
            }
            else if (strAction == "undosettlement")
            {
                if (strOldState != "settlemented")
                {
                    strError = "撤销结算操作前,记录状态必须为settlemented。(但发现为'" + strOldState + "')";
                    return -1;
                }
                if (strOldState == "amerced")
                {
                    strError = "撤销结算操作前,记录状态已经为settlemented";
                    return -1;
                }
            }
            else if (strAction == "delete")
            {
                if (strOldState != "settlemented")
                {
                    strError = "删除结算操作前,记录状态必须为settlemented。(但发现为'" + strOldState + "')";
                    return -1;
                }
            }
            else
            {
                strError = "无法识别的strAction参数值 '" + strAction + "'";
                return -1;
            }

            byte[] output_timestamp = null;

            if (bCreateOperLog == true)
            {
                // oldAmerceRecord
                XmlNode nodeOldAmerceRecord = DomUtil.SetElementText(domOperLog.DocumentElement,
    "oldAmerceRecord", strAmercedXml);
                DomUtil.SetAttr(nodeOldAmerceRecord, "recPath", strAmercedRecPath);
            }

            if (strAction == "delete")
            {
                // 删除已结算违约金记录
                lRet = channel.DoDeleteRes(strAmercedRecPath,
                    amerced_timestamp,
                    out output_timestamp,
                    out strError);
                if (lRet == -1)
                {
                    if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch
                        && nRedoCount < 10)
                    {
                        nRedoCount++;
                        amerced_timestamp = output_timestamp;
                        goto REDO;
                    }
                    strError = "删除已结算违约金记录 '" + strAmercedRecPath + "' 失败: " + strError;
                    this.WriteErrorLog(strError);
                    return -1;
                }

                goto END1;  // 写日志
            }

            // 修改状态
            if (strAction == "settlement")
            {
                DomUtil.SetElementText(amerced_dom.DocumentElement,
                    "state", "settlemented");


                // 清除两个信息
                DomUtil.DeleteElement(amerced_dom.DocumentElement,
                    "undoSettlementOperTime");
                DomUtil.DeleteElement(amerced_dom.DocumentElement,
                    "undoSettlementOperator");


                DomUtil.SetElementText(amerced_dom.DocumentElement,
                    "settlementOperTime", strOperTime);
                DomUtil.SetElementText(amerced_dom.DocumentElement,
                    "settlementOperator", strOperator);
            }
            else
            {
                Debug.Assert(strAction == "undosettlement", "");

                DomUtil.SetElementText(amerced_dom.DocumentElement,
                    "state", "amerced");


                // 清除两个信息
                DomUtil.SetElementText(amerced_dom.DocumentElement,
                    "settlementOperTime", "");
                DomUtil.SetElementText(amerced_dom.DocumentElement,
                    "settlementOperator", "");


                DomUtil.SetElementText(amerced_dom.DocumentElement,
                    "undoSettlementOperTime", strOperTime);
                DomUtil.SetElementText(amerced_dom.DocumentElement,
                    "undoSettlementOperator", strOperator);

            }

            if (bCreateOperLog == true)
            {
                DomUtil.SetElementText(domOperLog.DocumentElement, "operator",
                    strOperator);   // 操作者
                DomUtil.SetElementText(domOperLog.DocumentElement, "operTime",
                    strOperTime);   // 操作时间
            }


            // 保存回数据库
            lRet = channel.DoSaveTextRes(strAmercedRecPath,
                amerced_dom.OuterXml,
                false,
                "content", // ?????,ignorechecktimestamp
                amerced_timestamp,
                out output_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                strError = "写回违约金记录 '" + strAmercedRecPath + "' 时出错: " + strError;
                return -1;
            }

            if (bCreateOperLog == true)
            {
                // amerceRecord
                XmlNode nodeAmerceRecord = DomUtil.SetElementText(domOperLog.DocumentElement,
                    "amerceRecord", amerced_dom.OuterXml);
                DomUtil.SetAttr(nodeAmerceRecord, "recPath", strAmercedRecPath);
            }


        END1:
            if (bCreateOperLog == true)
            {
                if (this.Statis != null)
                {
                    if (strAction == "settlement")
                        this.Statis.IncreaseEntryValue(
                            strLibraryCode,
                            "费用结算", "结算记录数", 1);
                    else if (strAction == "undosettlement")
                        this.Statis.IncreaseEntryValue(
                            strLibraryCode,
                            "费用结算", "撤销结算记录数", 1);
                    else if (strAction == "delete")
                        this.Statis.IncreaseEntryValue(
                            strLibraryCode,
                            "费用结算", "删除结算记录数", 1);
                }


                nRet = this.OperLog.WriteOperLog(domOperLog,
                    strClientAddress,
                    out strError);
                if (nRet == -1)
                {
                    strError = "settlement() API 写入日志时发生错误: " + strError;
                    return -2;
                }
            }

            return 0;
        }
Exemplo n.º 12
0
        // text-level: 内部处理
        // 在 预约到书 库中,追加一条新的记录
        // 并作email通知
        // 注:本函数可能要删除部分通知记录
        // parameters:
        //      strItemBarcode  册条码号。必须是册条码号。如果册条码号为空,参考ID需要使用 strRefID 参数
        //      strRefID        参考ID
        //      bOnShelf    要通知的册是否在架。在架指并没有人借阅过,本来就在书架上。
        //      strLibraryCode  读者所在的馆代码
        //      strReaderXml    预约了图书的读者的XML记录。用于消息通知接口
        int AddNotifyRecordToQueue(
            // RmsChannelCollection channels,
            RmsChannel channel,
            string strItemBarcode,
            string strRefID,
            string strItemXml,
            bool bOnShelf,
            string strLibraryCode,
            string strReaderBarcode,
            string strReaderXml,
            out List<string> DeletedNotifyRecPaths,
            out string strError)
        {
            strError = "";
            DeletedNotifyRecPaths = new List<string>();
            
            // 2010/12/31
            if (String.IsNullOrEmpty(this.ArrivedDbName) == true)
            {
                strError = "预约到书库尚未定义, AddNotifyRecordToQueue()调用失败";
                return -1;
            }

            // 准备写记录
            byte[] timestamp = null;
            byte[] output_timestamp = null;
            string strOutputPath = "";
            int nRet = 0;
            long lRet = 0;

            if (String.IsNullOrEmpty(strItemBarcode) == true)
            {
                // 如果检索用的册条码号为空,加上对命中结果数量不设限,那就会造成系统严重繁忙。
                strError = "参数strItemBarcode中的册条码号不能为空。";
                return -1;
            }

#if NO
            RmsChannel channel = channels.GetChannel(this.WsUrl);
            if (channel == null)
            {
                strError = "get channel error";
                return -1;
            }
#endif

        REDODELETE:
            // 如果队列中已经存在同册条码号的记录, 要先删除
            string strNotifyXml = "";
            // 获得预约到书队列记录
            // return:
            //      -1  error
            //      0   not found
            //      1   命中1条
            //      >1  命中多于1条
            nRet = GetArrivedQueueRecXml(
                // channels,
                channel,
                strItemBarcode,
                out strNotifyXml,
                out timestamp,
                out strOutputPath,
                out strError);
            if (nRet == -1)
            {
                // 写入错误日志?
                this.WriteErrorLog("在还书操作中,检索册条码号为 " + strItemBarcode + " 的预约到书库记录时出错: " + strError);
            }
            if (nRet >= 1)
            {
                int nRedoDeleteCount = 0;
            // TODO: 这一段删除代码可以专门编制在一个函数中,不必这么费力循环。可以优化处理
            REDO_DELETE:
                lRet = channel.DoDeleteRes(strOutputPath,
                    timestamp,
                    out output_timestamp,
                    out strError);
                if (lRet == -1)
                {
                    // 时间戳不匹配
                    if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch
                        && nRedoDeleteCount < 10)
                    {
                        nRedoDeleteCount++;
                        timestamp = output_timestamp;
                        goto REDO_DELETE;
                    }

                    // 写入错误日志?
                    this.WriteErrorLog("在还书操作中,加入新预约到书记录前, 删除已存在的预约到书库记录 '" + strOutputPath + "' 出错: " + strError);
                }

                DeletedNotifyRecPaths.Add(strOutputPath);    // 记忆已经被删除的记录路径 2007/7/5 

                goto REDODELETE;    // 如果有多条,循环删除
            }

            XmlDocument itemdom = null;
            nRet = LibraryApplication.LoadToDom(strItemXml,
                out itemdom,
                out strError);
            if (nRet == -1)
            {
                strError = "装载册记录 '"+strItemBarcode+"' 的 XML 进入 DOM 时发生错误: " + strError;
                return -1;
            }

            string strLocation = DomUtil.GetElementText(itemdom.DocumentElement, "location");
            strLocation = StringUtil.GetPureLocationString(strLocation);

            // 创建预约到书记录
            XmlDocument new_queue_dom = new XmlDocument();
            new_queue_dom.LoadXml("<root />");

            // TODO: 以后增加 <refID> 元素,存储册记录的参考ID

#if NO
            XmlNode nodeItemBarcode = DomUtil.SetElementText(dom.DocumentElement, "itemBarcode", strItemBarcode);

            // 在<itemBarcode>元素中增加一个onShelf属性,表示属于在架情况
            Debug.Assert(nodeItemBarcode != null, "");
            if (bOnShelf == true)
                DomUtil.SetAttr(nodeItemBarcode, "onShelf", "true");
#endif
            // 兼容 strItemBarcode 中含有前缀的用法
            string strHead = "@refID:";
            if (StringUtil.HasHead(strItemBarcode, strHead, true) == true)
            {
                strRefID = strItemBarcode.Substring(strHead.Length);
                strItemBarcode = "";
            }

            if (this.ArrivedDbKeysContainsRefIDKey() == true)
            {
                DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", strItemBarcode);
                DomUtil.SetElementText(new_queue_dom.DocumentElement, "refID", strRefID);
            }
            else
            {
                if (string.IsNullOrEmpty(strItemBarcode) == true)
                {
                    if (string.IsNullOrEmpty(strRefID) == true)
                    {
                        strError = "AddNotifyRecordToQueue() 函数当 strItemBarcode 参数为空的时候,必须让 strRefID 参数不为空";
                        return -1;
                    }

                    Debug.Assert(string.IsNullOrEmpty(strRefID) == false, "");
                    // 旧的用法。避免检索时候查不到
                    DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", "@refID:" + strRefID);
                }
                else
                    DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", strItemBarcode); // 2015/5/20 添加,修正 BUG
            }

            // 改为存储在元素中 2015/5/7
            if (bOnShelf == true)
                DomUtil.SetElementText(new_queue_dom.DocumentElement, "onShelf", "true");

            // 2012/10/26
            DomUtil.SetElementText(new_queue_dom.DocumentElement, "libraryCode", strLibraryCode);

            DomUtil.SetElementText(new_queue_dom.DocumentElement, "readerBarcode", strReaderBarcode);
            DomUtil.SetElementText(new_queue_dom.DocumentElement, "notifyDate", this.Clock.GetClock());

            // 2015/6/13
            DomUtil.SetElementText(new_queue_dom.DocumentElement, "location", strLocation);

            string strPath = this.ArrivedDbName + "/?";

            // 写新记录
            lRet = channel.DoSaveTextRes(
                strPath,
                new_queue_dom.OuterXml,
                false,
                "content,ignorechecktimestamp",
                timestamp,
                out output_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                // 写入错误日志 2007/1/3 
                this.WriteErrorLog("创建新的预约到书队列记录时出错: " + strError);
                return -1;
            }

            string strReaderEmailAddress = "";
            string strName = "";
            nRet = GetReaderNotifyInfo(
                strReaderXml,
                out strName,
                out strReaderEmailAddress,
                out strError);
            if (nRet == -1)
                return -1;

            // 获得图书摘要信息
            string strSummary = "";
            string strBiblioRecPath = "";

            nRet = this.GetBiblioSummary(strItemBarcode,
                "", //  strConfirmItemRecPath,
                null,   //  strBiblioRecPathExclude,
                25,
                out strBiblioRecPath,
                out strSummary,
                out strError);
            if (nRet == -1)
            {
                strSummary = "ERROR: " + strError;
            }
#if NO
            // 临时的SessionInfo对象
            SessionInfo sessioninfo = new SessionInfo(this);
            // 模拟一个账户
            Account account = new Account();
            account.LoginName = "CacheBuilder";
            account.Password = "";
            account.Rights = "getbibliosummary";

            account.Type = "";
            account.Barcode = "";
            account.Name = "AddNotifyRecordToQueue";
            account.UserID = "AddNotifyRecordToQueue";
            account.RmsUserName = this.ManagerUserName;
            account.RmsPassword = this.ManagerPassword;

            sessioninfo.Account = account;
            try
            {

                string strBiblioRecPath = "";
                LibraryServerResult result = this.GetBiblioSummary(
                    sessioninfo,
                    strItemBarcode,
                    "", // strConfirmItemRecPath,
                    null,
                    out strBiblioRecPath,
                    out strSummary);
                if (result.Value == -1)
                {
                    strSummary = "ERROR: " + result.ErrorInfo;
                }
                else
                {
                    // 截断
                    if (strSummary.Length > 25)
                        strSummary = strSummary.Substring(0, 25) + "...";
                }
            }
            finally
            {
                sessioninfo.Close();
                sessioninfo = null;
            }
#endif


            // 发送短消息通知
            string strTotalError = "";

            // *** dpmail
            if (this.MessageCenter != null)
            {
                string strTemplate = "";
                // 获得邮件模板
                nRet = GetMailTemplate(
                    "dpmail",
                    bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)",
                    out strTemplate,
                    out strError);
                if (nRet == -1)
                    return -1;
                if (nRet == 0)
                {
                    strError = "预约到书通知<mailTemplate/template>尚未配置。";
                    return -1;
                }

                /*
                %item%  册信息
                %reservetime%   保留期限
                %today% 发出email的当天
                %summary% 书目摘要
                %itembarcode% 册条码号 
                %name% 读者姓名
                 * */
                Hashtable table = new Hashtable();
                table["%item%"] = "(册条码号为: " + strItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strItemBarcode + " )";
                table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan);
                table["%today%"] = DateTime.Now.ToString();
                table["%summary%"] = strSummary;
                table["%itembarcode%"] = strItemBarcode;
                table["%name%"] = strName;
                string strBody = "";

                nRet = GetMailText(strTemplate,
                    table,
                    out strBody,
                    out strError);
                if (nRet == -1)
                    return -1;

                if (String.IsNullOrEmpty(this.MessageCenter.MessageDbName) == false)
                {
                    Debug.Assert(channel.Container != null, "");
                    // 发送消息
                    nRet = this.MessageCenter.SendMessage(
                        channel.Container,  // channels,
                        strReaderBarcode,
                        "图书馆",
                        "预约到书通知",
                        "text",
                        strBody,
                        false,
                        out strError);
                    if (nRet == -1)
                    {
                        strTotalError += "发送dpmail消息时出错: " + strError + "\r\n";
                    }
                }
            }

            // ** email
            if (String.IsNullOrEmpty(strReaderEmailAddress) == false)
            {
                string strTemplate = "";
                // 获得邮件模板
                nRet = GetMailTemplate(
                    "email",
                    bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)",
                    out strTemplate,
                    out strError);
                if (nRet == -1)
                    return -1;
                if (nRet == 0)
                {
                    strError = "预约到书通知<mailTemplate/template>尚未配置。";
                    return -1;
                }

                /*
                %item%  册信息
                %reservetime%   保留期限
                %today% 发出email的当天
                %summary% 书目摘要
                %itembarcode% 册条码号 
                %name% 读者姓名
                 * */
                Hashtable table = new Hashtable();
                table["%item%"] = "(册条码号为: " + strItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strItemBarcode + " )";
                table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan);
                table["%today%"] = DateTime.Now.ToString();
                table["%summary%"] = strSummary;
                table["%itembarcode%"] = strItemBarcode;
                table["%name%"] = strName;

                string strBody = "";

                nRet = GetMailText(strTemplate,
                    table,
                    out strBody,
                    out strError);
                if (nRet == -1)
                    return -1;

                {
                    // 发送email
                    // return:
                    //      -1  error
                    //      0   not found smtp server cfg
                    //      1   succeed
                    nRet = SendEmail(strReaderEmailAddress,
                        "预约到书通知",
                        strBody,
                        "text",
                        out strError);
                    if (nRet == -1)
                    {
                        strTotalError += "发送email消息时出错: " + strError + "\r\n";
                    }
                }
            }

            // *** external messageinterfaces
            if (this.m_externalMessageInterfaces != null)
            {
                foreach (MessageInterface message_interface in this.m_externalMessageInterfaces)
                {
                    string strTemplate = "";
                    // 获得邮件模板
                    nRet = GetMailTemplate(
                        message_interface.Type,
                        bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)",
                        out strTemplate,
                        out strError);
                    if (nRet == -1)
                        return -1;
                    if (nRet == 0)
                    {
                        strError = "预约到书通知<mailTemplate/template>尚未配置。";
                        return -1;
                    }

                    /*
                    %item%  册信息
                    %reservetime%   保留期限
                    %today% 发出email的当天
                %summary% 书目摘要
                %itembarcode% 册条码号 
                %name% 读者姓名
                     * */
                    Hashtable table = new Hashtable();
                    table["%item%"] = "(册条码号为: " + strItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strItemBarcode + " )";
                    table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan);
                    table["%today%"] = DateTime.Now.ToString();
                    table["%summary%"] = strSummary;
                    table["%itembarcode%"] = strItemBarcode;
                    table["%name%"] = strName;

                    string strBody = "";

                    nRet = GetMailText(strTemplate,
                        table,
                        out strBody,
                        out strError);
                    if (nRet == -1)
                        return -1;

                    // 发送消息
                    nRet = message_interface.HostObj.SendMessage(
                        strReaderBarcode,
                        strReaderXml,
                        strBody,
                        strLibraryCode,
                        out strError);
                    if (nRet == -1)
                    {
                        strTotalError += "发送"+message_interface.Type+"消息时出错: " + strError + "\r\n";
                    }
                }
            }

            if (String.IsNullOrEmpty(strTotalError) == false)
            {
                strError = strTotalError;
                return -1;
            }

            return 0;
        }
Exemplo n.º 13
0
        // 删除属于同一书目记录的全部实体记录
        // 这是需要提供EntityInfo数组的版本
        // return:
        //      -1  error
        //      0   没有找到属于书目记录的任何实体记录,因此也就无从删除
        //      >0  实际删除的实体记录数
        public int DeleteBiblioChildEntities(RmsChannel channel,
            List<DeleteEntityInfo> entityinfos,
            XmlDocument domOperLog,
            out string strError)
        {
            strError = "";

            if (entityinfos == null || entityinfos.Count == 0)
                return 0;

            int nDeletedCount = 0;

            XmlNode root = null;

            if (domOperLog != null)
            {
                root = domOperLog.CreateElement("deletedEntityRecords");
                domOperLog.DocumentElement.AppendChild(root);
            }

            // 真正实行删除
            for (int i = 0; i < entityinfos.Count; i++)
            {
                DeleteEntityInfo info = entityinfos[i];

                byte[] output_timestamp = null;
                int nRedoCount = 0;

            REDO_DELETE:

                this.EntityLocks.LockForWrite(info.ItemBarcode);
                try
                {

                    long lRet = channel.DoDeleteRes(info.RecPath,
                        info.OldTimestamp,
                        out output_timestamp,
                        out strError);
                    if (lRet == -1)
                    {
                        if (channel.ErrorCode == ChannelErrorCode.NotFound)
                            continue;

                        // 如果不重试,让时间戳出错暴露出来。
                        // 如果要重试,也得加上重新读入册记录并判断重新判断无借还信息才能删除

                        if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                        {
                            if (nRedoCount > 10)
                            {
                                strError = "重试了10次还不行。删除实体记录 '" + info.RecPath + "' 时发生错误: " + strError;
                                goto ERROR1;
                            }
                            nRedoCount++;

                            // 重新读入记录
                            string strMetaData = "";
                            string strXml = "";
                            string strOutputPath = "";
                            string strError_1 = "";

                            lRet = channel.GetRes(info.RecPath,
                                out strXml,
                                out strMetaData,
                                out output_timestamp,
                                out strOutputPath,
                                out strError_1);
                            if (lRet == -1)
                            {
                                if (channel.ErrorCode == ChannelErrorCode.NotFound)
                                    continue;

                                strError = "在删除实体记录 '" + info.RecPath + "' 时发生时间戳冲突,于是自动重新获取记录,但又发生错误: " + strError_1;
                                goto ERROR1;
                                // goto CONTINUE;
                            }

                            // 检查是否有借阅信息
                            // 把记录装入DOM
                            XmlDocument domExist = new XmlDocument();

                            try
                            {
                                domExist.LoadXml(strXml);
                            }
                            catch (Exception ex)
                            {
                                strError = "实体记录 '"+info.RecPath+"' XML装载进入DOM时发生错误: " + ex.Message;
                                goto ERROR1;
                            }

                            info.ItemBarcode = DomUtil.GetElementText(domExist.DocumentElement,
                                "barcode");

                            // 观察已经存在的记录是否有流通信息
                            string strDetail = "";
                            bool bHasCirculationInfo = IsEntityHasCirculationInfo(domExist,
                                out strDetail);
                            if (bHasCirculationInfo == true)
                            {
                                strError = "拟删除的册记录 '" + info.RecPath + "' 中包含有流通信息("+strDetail+")(此种情况可能不限于这一条),不能删除。";
                                goto ERROR1;
                            }


                            info.OldTimestamp = output_timestamp;
                            goto REDO_DELETE;
                        }

                        strError = "删除实体记录 '" + info.RecPath + "' 时发生错误: " + strError;
                        goto ERROR1;
                    }
                }
                finally
                {
                    this.EntityLocks.UnlockForWrite(info.ItemBarcode);
                }

                // 增补到日志DOM中
                if (domOperLog != null)
                {
                    Debug.Assert(root != null, "");

                    XmlNode node = domOperLog.CreateElement("record");
                    root.AppendChild(node);

                    DomUtil.SetAttr(node, "recPath", info.RecPath);
                }

                nDeletedCount++;
            }


            return nDeletedCount;
        ERROR1:
            return -1;
        }
Exemplo n.º 14
0
        // 复制属于同一书目记录的全部实体记录
        // parameters:
        //      strAction   copy / move
        // return:
        //      -2  目标实体库不存在,无法进行复制或者删除
        //      -1  error
        //      >=0  实际复制或者移动的实体记录数
        public int CopyBiblioChildEntities(RmsChannel channel,
            string strAction,
            List<DeleteEntityInfo> entityinfos,
            string strTargetBiblioRecPath,
            XmlDocument domOperLog,
            out string strError)
        {
            strError = "";

            if (entityinfos == null || entityinfos.Count == 0)
                return 0;

            int nOperCount = 0;

            XmlNode root = null;

            if (domOperLog != null)
            {
                root = domOperLog.CreateElement(strAction == "copy" ? "copyEntityRecords" : "moveEntityRecords");
                domOperLog.DocumentElement.AppendChild(root);
            }

            // 获得目标书目库下属的实体库名
            string strTargetItemDbName = "";
            string strTargetBiblioDbName = ResPath.GetDbName(strTargetBiblioRecPath);
            // return:
            //      -1  出错
            //      0   没有找到
            //      1   找到
            int nRet = this.GetItemDbName(strTargetBiblioDbName,
                out strTargetItemDbName,
                out strError);
            if (nRet == 0 || string.IsNullOrEmpty(strTargetItemDbName) == true)
            {
                return -2;   // 目标实体库不存在
            }

            string strParentID = ResPath.GetRecordId(strTargetBiblioRecPath);
            if (string.IsNullOrEmpty(strParentID) == true)
            {
                strError = "目标书目记录路径 '"+strTargetBiblioRecPath+"' 不正确,无法获得记录号";
                return -1;
            }

            List<string> newrecordpaths = new List<string>();
            List<string> oldrecordpaths = new List<string>();
            List<string> parentids = new List<string>();
            List<string> oldrecords = new List<string>();

            for (int i = 0; i < entityinfos.Count; i++)
            {
                DeleteEntityInfo info = entityinfos[i];

                byte[] output_timestamp = null;
                string strOutputRecPath = "";

                string strNewBarcode = "";  // 复制中修改后的册条码号

                this.EntityLocks.LockForWrite(info.ItemBarcode);
                try
                {
                    XmlDocument dom = new XmlDocument();
                    try
                    {
                        dom.LoadXml(info.OldRecord);
                    }
                    catch (Exception ex)
                    {
                        strError = "记录 '" + info.RecPath + "' 装入XMLDOM发生错误: " + ex.Message;
                        goto ERROR1;
                    }
                    DomUtil.SetElementText(dom.DocumentElement,
                        "parent",
                        strParentID);

                    // 复制的情况,要避免出现操作后的条码号重复现象
                    if (strAction == "copy")
                    {
                        // 修改册条码号,避免发生条码号重复
                        string strOldItemBarcode = DomUtil.GetElementText(dom.DocumentElement,
                            "barcode");
                        if (String.IsNullOrEmpty(strOldItemBarcode) == false)
                        {
                            strNewBarcode = strOldItemBarcode + "_" + Guid.NewGuid().ToString();
                            DomUtil.SetElementText(dom.DocumentElement,
                                "barcode",
                                strNewBarcode);
                        }

                        // *** 后面这几个清除动作要作为规则出现

                        // 清除 refid
                        DomUtil.SetElementText(dom.DocumentElement,
                            "refID",
                            null);


                        // 把借者清除
                        // (源实体记录中如果有借阅信息,在普通界面上是无法删除此记录的。只能用出纳窗正规进行归还,然后才能删除)
                        {
                            DomUtil.SetElementText(dom.DocumentElement,
                                "borrower",
                                null);
                            DomUtil.SetElementText(dom.DocumentElement,
                                "borrowPeriod",
                                null);
                            DomUtil.SetElementText(dom.DocumentElement,
                                "borrowDate",
                                null);
                        }
                    }

                    // TODO: 可以顺便确认有没有对象资源。如果没有,就省略CopyRecord操作

                    long lRet = channel.DoCopyRecord(info.RecPath,
                         strTargetItemDbName + "/?",
                         strAction == "move" ? true : false,   // bDeleteSourceRecord
                         out output_timestamp,
                         out strOutputRecPath,
                         out strError);
                    if (lRet == -1)
                    {
                        if (channel.ErrorCode == ChannelErrorCode.NotFound)
                            continue;
                        strError = "复制实体记录 '" + info.RecPath + "' 时发生错误: " + strError;
                        goto ERROR1;
                    }



                    // 修改xml记录。<parent>元素发生了变化
                    byte[] baOutputTimestamp = null;
                    string strOutputRecPath1 = "";
                    lRet = channel.DoSaveTextRes(strOutputRecPath,
                        dom.OuterXml,
                        false,
                        "content", // ,ignorechecktimestamp
                        output_timestamp,
                        out baOutputTimestamp,
                        out strOutputRecPath1,
                        out strError);
                    if (lRet == -1)
                        goto ERROR1;

                    oldrecordpaths.Add(info.RecPath);
                    newrecordpaths.Add(strOutputRecPath);
                    parentids.Add(strParentID);
                    if (strAction == "move")
                        oldrecords.Add(info.OldRecord);
                }
                finally
                {
                    this.EntityLocks.UnlockForWrite(info.ItemBarcode);
                }

                // 增补到日志DOM中
                if (domOperLog != null)
                {
                    Debug.Assert(root != null, "");

                    XmlNode node = domOperLog.CreateElement("record");
                    root.AppendChild(node);

                    DomUtil.SetAttr(node, "recPath", info.RecPath);
                    DomUtil.SetAttr(node, "targetRecPath", strOutputRecPath);

                    // 2014/1/5
                    if (string.IsNullOrEmpty(strNewBarcode) == false)
                        DomUtil.SetAttr(node, "newBarcode", strNewBarcode);
                }

                nOperCount++;
            }


            return nOperCount;
        ERROR1:
            // Undo已经进行过的操作
            if (strAction == "copy")
            {
                string strWarning = "";

                foreach (string strRecPath in newrecordpaths)
                {
                    string strTempError = "";
                    byte[] timestamp = null;
                    byte[] output_timestamp = null;
                REDO_DELETE:
                    long lRet = channel.DoDeleteRes(strRecPath,
                        timestamp,
                        out output_timestamp,
                        out strTempError);
                    if (lRet == -1)
                    {
                        if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                        {
                            if (timestamp == null)
                            {
                                timestamp = output_timestamp;
                                goto REDO_DELETE;
                            }
                        }
                        strWarning += strTempError + ";";
                    }

                }
                if (string.IsNullOrEmpty(strWarning) == false)
                    strError = strError + "。在Undo过程中,又遇到出错: " + strWarning;
            }
            else if (strAction == "move")
            {
                string strWarning = "";
                for (int i = 0; i < newrecordpaths.Count; i++)
                {
                    byte[] output_timestamp = null;
                    string strOutputRecPath = "";
                    string strTempError = "";
                    // TODO: 如果确认没有对象,就可以省略这一步
                    long lRet = channel.DoCopyRecord(newrecordpaths[i],
         oldrecordpaths[i],
         true,   // bDeleteSourceRecord
         out output_timestamp,
         out strOutputRecPath,
         out strTempError);
                    if (lRet == -1)
                    {
                        strWarning += strTempError + ";";
                    }

                    // 修改xml记录。<parent>元素发生了变化
                    byte[] baOutputTimestamp = null;
                    string strOutputRecPath1 = "";
                    lRet = channel.DoSaveTextRes(oldrecordpaths[i],
                        oldrecords[i],
                        false,
                        "content", // ,ignorechecktimestamp
                        output_timestamp,
                        out baOutputTimestamp,
                        out strOutputRecPath1,
                        out strTempError);
                    if (lRet == -1)
                    {
                        strWarning += strTempError + ";";
                    }
                }
                if (string.IsNullOrEmpty(strWarning) == false)
                    strError = strError + "。在Undo过程中,又遇到出错: " + strWarning;
            }
            return -1;
        }
Exemplo n.º 15
0
        // 删除册记录的操作
        int DoEntityOperDelete(
            SessionInfo sessioninfo,
            bool bForce,
            string strStyle,
            RmsChannel channel,
            EntityInfo info,
            string strOldBarcode,
            string strNewBarcode,   // TODO: 本参数是否可以废除?
            XmlDocument domOldRec,
            ref XmlDocument domOperLog,
            ref List<EntityInfo> ErrorInfos)
        {
            int nRedoCount = 0;
            EntityInfo error = null;
            int nRet = 0;
            long lRet = 0;
            string strError = "";

            // 2008/6/24 
            if (String.IsNullOrEmpty(info.NewRecPath) == false)
            {
                if (info.NewRecPath != info.OldRecPath)
                {
                    strError = "action为delete时, 如果info.NewRecPath不空,则其内容必须和info.OldRecPath一致。(info.NewRecPath='" + info.NewRecPath + "' info.OldRecPath='" + info.OldRecPath + "')";
                    return -1;
                }
            }
            else
            {
                info.NewRecPath = info.OldRecPath;
            }


            // 如果记录路径为空, 则先获得记录路径
            if (String.IsNullOrEmpty(info.NewRecPath) == true)
            {
                List<string> aPath = null;

                if (String.IsNullOrEmpty(strOldBarcode) == true)
                {
                    strError = "info.OldRecord中的<barcode>元素中的册条码号,和info.RecPath参数值,不能同时为空。";
                    goto ERROR1;
                }

                // 本函数只负责查重, 并不获得记录体
                // return:
                //      -1  error
                //      其他    命中记录条数(不超过nMax规定的极限)
                nRet = this.SearchItemRecDup(
                    // sessioninfo.Channels,
                    channel,
                    strOldBarcode,
                    100,
                    out aPath,
                    out strError);
                if (nRet == -1)
                {
                    strError = "删除操作中条码号查重阶段发生错误:" + strError;
                    goto ERROR1;
                }

                if (nRet == 0)
                {
                    error = new EntityInfo(info);
                    error.ErrorInfo = "册条码号为 '" + strOldBarcode + "' 的册记录已不存在";
                    error.ErrorCode = ErrorCodeValue.NotFound;
                    ErrorInfos.Add(error);
                    return -1;
                }

                if (nRet > 1)
                {
                    /*
                    string[] pathlist = new string[aPath.Count];
                    aPath.CopyTo(pathlist);
                     * */

                    // 在删除操作中,遇到重复的是很平常的事情。只要
                    // info.OldRecPath能够清晰地指出要删除的那一条,就可以执行删除
                    if (String.IsNullOrEmpty(info.OldRecPath) == false)
                    {
                        if (aPath.IndexOf(info.OldRecPath) == -1)
                        {
                            strError = "条码号 '" + strOldBarcode + "' 已经被下列多条册记录使用了: " + StringUtil.MakePathList(aPath)/*String.Join(",", pathlist)*/ + "',但并不包括info.OldRecPath所指的路径 '" + info.OldRecPath + "'。删除操作失败。";
                            goto ERROR1;
                        }
                        info.NewRecPath = info.OldRecPath;
                    }
                    else
                    {
                        strError = "条码号 '" + strOldBarcode + "' 已经被下列多条册记录使用了: " + StringUtil.MakePathList(aPath)/*String.Join(",", pathlist)*/ + "',在没有指定info.OldRecPath的情况下,无法定位和删除。";
                        goto ERROR1;
                    }
                }
                else
                {
                    Debug.Assert(nRet == 1, "");

                    info.NewRecPath = aPath[0];
                    // strEntityDbName = ResPath.GetDbName(strRecPath);
                }
            }

            Debug.Assert(String.IsNullOrEmpty(info.NewRecPath) == false, "");
            // Debug.Assert(strEntityDbName != "", "");

            byte[] exist_timestamp = null;
            string strOutputPath = "";
            string strMetaData = "";
            string strExistingXml = "";

        REDOLOAD:

            // 先读出数据库中此位置的已有记录
            lRet = channel.GetRes(info.NewRecPath,
                out strExistingXml,
                out strMetaData,
                out exist_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                if (channel.ErrorCode == ChannelErrorCode.NotFound)
                {
                    error = new EntityInfo(info);
                    error.ErrorInfo = "册条码号为 '" + strOldBarcode + "' 的册记录 '" + info.NewRecPath + "' 已不存在";
                    error.ErrorCode = channel.OriginErrorCode;
                    ErrorInfos.Add(error);
                    return -1;
                }
                else
                {
                    error = new EntityInfo(info);
                    error.ErrorInfo = "删除操作发生错误, 在读入原有记录 '" + info.NewRecPath + "' 阶段:" + strError;
                    error.ErrorCode = channel.OriginErrorCode;
                    ErrorInfos.Add(error);
                    return -1;
                }
            }

            // 把记录装入DOM
            XmlDocument domExist = new XmlDocument();

            try
            {
                domExist.LoadXml(strExistingXml);
            }
            catch (Exception ex)
            {
                strError = "strExistXml装载进入DOM时发生错误: " + ex.Message;
                goto ERROR1;
            }

            // 观察已经存在的记录中,册条码号是否和strOldBarcode一致
            if (String.IsNullOrEmpty(strOldBarcode) == false)
            {
                string strExistingBarcode = DomUtil.GetElementText(domExist.DocumentElement, "barcode");
                if (strExistingBarcode != strOldBarcode)
                {
                    strError = "路径为 '" + info.NewRecPath + "' 的册记录中<barcode>元素中的册条码号 '" + strExistingBarcode + "' 和strOldXml中<barcode>元素中的册条码号 '" + strOldBarcode + "' 不一致。拒绝删除(如果允许删除,则会造成不经意删除了别的册记录的危险)。";
                    goto ERROR1;
                }
            }


            if (bForce == false)
            {
                // 观察已经存在的记录是否有流通信息
                string strDetail = "";
                bool bHasCirculationInfo = IsEntityHasCirculationInfo(domExist,
                    out strDetail);

                if (bHasCirculationInfo == true)
                {
                    strError = "拟删除的册记录 '" + info.NewRecPath + "' 中包含有流通信息(" + strDetail + "),不能删除。";
                    goto ERROR1;
                }
            }

            // 比较时间戳
            // 观察时间戳是否发生变化
            nRet = ByteArray.Compare(info.OldTimestamp, exist_timestamp);
            if (nRet != 0)
            {
                // 2008/5/29 
                if (bForce == true)
                {
                    error = new EntityInfo(info);
                    error.NewTimestamp = exist_timestamp;   // 让前端知道库中记录实际上发生过变化
                    error.ErrorInfo = "数据库中即将删除的册记录已经发生了变化,请重新装载、仔细核对后再行删除。";
                    error.ErrorCode = ErrorCodeValue.TimestampMismatch;
                    ErrorInfos.Add(error);
                    return -1;
                }

                // 如果前端给出了旧记录,就有和库中记录进行比较的基础
                if (String.IsNullOrEmpty(info.OldRecord) == false)
                {
                    // 比较两个记录, 看看和册要害信息有关的字段是否发生了变化
                    // return:
                    //      0   没有变化
                    //      1   有变化
                    nRet = IsRegisterInfoChanged(domExist,
                        domOldRec);
                    if (nRet == 1)
                    {

                        error = new EntityInfo(info);
                        error.NewTimestamp = exist_timestamp;   // 让前端知道库中记录实际上发生过变化
                        error.ErrorInfo = "数据库中即将删除的册记录已经发生了变化,请重新装载、仔细核对后再行删除。";
                        error.ErrorCode = ErrorCodeValue.TimestampMismatch;
                        ErrorInfos.Add(error);
                        return -1;
                    }
                }

                info.OldTimestamp = exist_timestamp;
                info.NewTimestamp = exist_timestamp;
            }

            // 只有order权限的情况
            if (StringUtil.IsInList("setiteminfo", sessioninfo.RightsOrigin) == false
                && StringUtil.IsInList("setentities", sessioninfo.RightsOrigin) == false
                && StringUtil.IsInList("order", sessioninfo.RightsOrigin) == true)
            {
                // 2009/11/26 changed
                string strEntityDbName = ResPath.GetDbName(info.NewRecPath);
                if (String.IsNullOrEmpty(strEntityDbName) == true)
                {
                    strError = "从路径 '" + info.NewRecPath + "' 中获得数据库名时失败";
                    goto ERROR1;
                }

                string strBiblioDbName = "";

                // 根据实体库名, 找到对应的书目库名
                // 注意,返回1的时候,strBiblioDbName也有可能为空
                // return:
                //      -1  出错
                //      0   没有找到
                //      1   找到
                nRet = GetBiblioDbNameByItemDbName(strEntityDbName,
                out strBiblioDbName,
                out strError);
                if (nRet == 0 || nRet == -1)
                {
                    strError = "根据实体库名 '" + strEntityDbName + "' 中获得书目库名时失败";
                    goto ERROR1;
                }

                // BUG !!! string strBiblioDbName = ResPath.GetDbName(info.NewRecPath);

                // 非工作库
                if (IsOrderWorkBiblioDb(strBiblioDbName) == false)
                {
                    // 非工作库。要求<state>包含“加工中”
                    string strState = DomUtil.GetElementText(domExist.DocumentElement,
                        "state");
                    if (IncludeStateProcessing(strState) == false)
                    {
                        strError = "当前帐户只有order权限而没有setiteminfo(或setentities)权限,不能用delete功能删除从属于非工作库的、状态不包含“加工中”的实体记录 '" + info.NewRecPath + "'";
                        goto ERROR1;    // TODO: 如何返回AccessDenied错误码呢?
                    }
                }
            }

            string strLibraryCode = "";
            // 检查一个册记录的馆藏地点是否符合馆代码列表要求
            // return:
            //      -1  检查过程出错
            //      0   符合要求
            //      1   不符合要求
            nRet = CheckItemLibraryCode(domExist,
                sessioninfo,
                        // sessioninfo.LibraryCodeList,
                        out strLibraryCode,
                        out strError);
            if (nRet == -1)
                goto ERROR1;



            // 检查旧记录是否属于管辖范围
            if (sessioninfo.GlobalUser == false)
            {
                if (nRet != 0)
                {
                    strError = "即将被删除的册记录 '" + info.NewRecPath + "' 其馆藏地点不符合要求: " + strError;
                    goto ERROR1;
                }
            }

            byte[] output_timestamp = null;

            lRet = channel.DoDeleteRes(info.NewRecPath,
                info.OldTimestamp,
                out output_timestamp,
                out strError);
            if (lRet == -1)
            {
                if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                {
                    if (nRedoCount > 10)
                    {
                        strError = "反复删除均遇到时间戳冲突, 超过10次重试仍然失败";
                        goto ERROR1;
                    }
                    // 发现时间戳不匹配
                    // 重复进行提取已存在记录\比较的过程
                    nRedoCount++;
                    goto REDOLOAD;
                }

                error = new EntityInfo(info);
                error.NewTimestamp = output_timestamp;
                error.ErrorInfo = "删除操作发生错误:" + strError;
                error.ErrorCode = channel.OriginErrorCode;
                ErrorInfos.Add(error);
                return -1;
            }
            else
            {
                // 成功
                DomUtil.SetElementText(domOperLog.DocumentElement,
    "libraryCode",
    strLibraryCode);    // 册所在的馆代码

                DomUtil.SetElementText(domOperLog.DocumentElement, "action", "delete");
                if (String.IsNullOrEmpty(strStyle) == false)
                    DomUtil.SetElementText(domOperLog.DocumentElement, "style", strStyle);

                // 不创建<record>元素

                XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement,
                    "oldRecord", strExistingXml);
                DomUtil.SetAttr(node, "recPath", info.NewRecPath);


                // 如果删除成功,则不必要在数组中返回表示成功的信息元素了
            }

            return 0;
        ERROR1:
            error = new EntityInfo(info);
            error.ErrorInfo = strError;
            error.ErrorCode = ErrorCodeValue.CommonError;
            ErrorInfos.Add(error);
            return -1;
        }