Esempio n. 1
0
        // 执行SetIssues API中的"change"操作
        // 1) 操作成功后, NewRecord中有实际保存的新记录,NewTimeStamp为新的时间戳
        // 2) 如果返回TimeStampMismatch错,则OldRecord中有库中发生变化后的“原记录”,OldTimeStamp是其时间戳
        // return:
        //      -1  出错
        //      0   成功
        static int DoIssueOperChange(
            RmsChannel channel,
            IssueInfo info,
            ref XmlDocument domOperLog,
            ref List<IssueInfo> ErrorInfos)
        {
            int nRedoCount = 0;
            IssueInfo error = null;
            bool bExist = true;    // info.RecPath所指的记录是否存在?

            int nRet = 0;
            long lRet = 0;

            string strError = "";

            // 检查一下路径
            if (String.IsNullOrEmpty(info.NewRecPath) == true)
            {
                strError = "info.NewRecPath中的路径不能为空";
                goto ERROR1;
            }

            string strTargetRecId = ResPath.GetRecordId(info.NewRecPath);

            if (strTargetRecId == "?")
            {
                strError = "info.NewRecPath路径 '" + strTargetRecId + "' 中记录ID部分不能为'?'";
                goto ERROR1;
            }
            if (String.IsNullOrEmpty(strTargetRecId) == true)
            {
                strError = "info.NewRecPath路径 '" + strTargetRecId + "' 中记录ID部分不能为空";
                goto ERROR1;
            }

            if (info.OldRecPath != info.NewRecPath)
            {
                strError = "当action为\"change\"时,info.NewRecordPath路径 '" + info.NewRecPath + "' 和info.OldRecPath '" + info.OldRecPath + "' 必须相同";
                goto ERROR1;
            }

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


            // 先读出数据库中即将覆盖位置的已有记录

        REDOLOAD:

            lRet = channel.GetRes(info.NewRecPath,
                out strExistXml,
                out strMetaData,
                out exist_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                if (channel.ErrorCode == ChannelErrorCode.NotFound)
                {
                    // 如果记录不存在, 则构造一条空的记录
                    bExist = false;
                    strExistXml = "<root />";
                    exist_timestamp = null;
                    strOutputPath = info.NewRecPath;
                }
                else
                {
                    error = new IssueInfo(info);
                    error.ErrorInfo = "保存操作发生错误, 在读入原有记录阶段:" + strError;
                    error.ErrorCode = channel.OriginErrorCode;
                    ErrorInfos.Add(error);
                    return -1;
                }
            }


            // 把两个记录装入DOM

            XmlDocument domExist = new XmlDocument();
            XmlDocument domNew = new XmlDocument();

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

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


            // 观察时间戳是否发生变化
            nRet = ByteArray.Compare(info.OldTimestamp, exist_timestamp);
            if (nRet != 0)
            {
                // 时间戳不相等了
                // 需要把info.OldRecord和strExistXml进行比较,看看和期记到有关的元素(要害元素)值是否发生了变化。
                // 如果这些要害元素并未发生变化,就继续进行合并、覆盖保存操作

                XmlDocument domOld = new XmlDocument();

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

                // 比较两个记录, 看看和期记到有关的字段是否发生了变化
                // return:
                //      0   没有变化
                //      1   有变化
                nRet = IsIssueInfoChanged(domOld,
                    domExist);
                if (nRet == 1)
                {
                    error = new IssueInfo(info);
                    // 错误信息中, 返回了修改过的原记录和新时间戳
                    error.OldRecord = strExistXml;
                    error.OldTimestamp = exist_timestamp;

                    if (bExist == false)
                        error.ErrorInfo = "保存操作发生错误: 数据库中的原记录已被删除。";
                    else
                        error.ErrorInfo = "保存操作发生错误: 数据库中的原记录已发生过修改";
                    error.ErrorCode = ErrorCodeValue.TimestampMismatch;
                    ErrorInfos.Add(error);
                    return -1;
                }

                // exist_timestamp此时已经反映了库中被修改后的记录的时间戳
            }


            // 合并新旧记录
            string strNewXml = "";
            nRet = MergeTwoIssueXml(domExist,
                domNew,
                out strNewXml,
                out strError);
            if (nRet == -1)
                goto ERROR1;


            // 保存新记录
            byte[] output_timestamp = null;
            lRet = channel.DoSaveTextRes(info.NewRecPath,
                strNewXml,
                false,   // include preamble?
                "content",
                exist_timestamp,
                out output_timestamp,
                out strOutputPath,
                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.ErrorInfo = "保存操作发生错误:" + strError;
                error.ErrorCode = channel.OriginErrorCode;
                ErrorInfos.Add(error);
                return -1;
            }
            else // 成功
            {
                DomUtil.SetElementText(domOperLog.DocumentElement, "action", "change");

                // 新记录
                XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement,
                    "record", strNewXml);
                DomUtil.SetAttr(node, "recPath", info.NewRecPath);

                // 旧记录
                node = DomUtil.SetElementText(domOperLog.DocumentElement,
                    "oldRecord", strExistXml);
                DomUtil.SetAttr(node, "recPath", info.OldRecPath);

                // 保存成功,需要返回信息元素。因为需要返回新的时间戳
                error = new IssueInfo(info);
                error.NewTimestamp = output_timestamp;
                error.NewRecord = strNewXml;

                error.ErrorInfo = "保存操作成功。NewTimeStamp中返回了新的时间戳,NewRecord中返回了实际保存的新记录(可能和提交的新记录稍有差异)。";
                error.ErrorCode = ErrorCodeValue.NoError;
                ErrorInfos.Add(error);
            }

            return 0;

        ERROR1:
            error = new IssueInfo(info);
            error.ErrorInfo = strError;
            error.ErrorCode = ErrorCodeValue.CommonError;
            ErrorInfos.Add(error);
            return -1;
        }
Esempio n. 2
0
        // 执行SetIssues API中的"move"操作
        // 1) 操作成功后, NewRecord中有实际保存的新记录,NewTimeStamp为新的时间戳
        // 2) 如果返回TimeStampMismatch错,则OldRecord中有库中发生变化后的“原记录”,OldTimeStamp是其时间戳
        // return:
        //      -1  出错
        //      0   成功
        int DoIssueOperMove(
            RmsChannel channel,
            IssueInfo info,
            ref XmlDocument domOperLog,
            ref List<IssueInfo> ErrorInfos)
        {
            // int nRedoCount = 0;
            IssueInfo error = null;
            bool bExist = true;    // info.RecPath所指的记录是否存在?

            int nRet = 0;
            long lRet = 0;

            string strError = "";

            // 检查路径
            if (info.OldRecPath == info.NewRecPath)
            {
                strError = "当action为\"move\"时,info.NewRecordPath路径 '" + info.NewRecPath + "' 和info.OldRecPath '" + info.OldRecPath + "' 必须不相同";
                goto ERROR1;
            }

            // 检查即将覆盖的目标位置是不是有记录,如果有,则不允许进行move操作。
            // 如果要进行带覆盖目标位置记录功能的move操作,前端可以先执行一个delete操作,然后再执行move操作。
            // 这样规定,是为了避免过于复杂的判断逻辑,也便于前端操作者清楚操作的后果。
            // 因为如果允许move带有覆盖目标记录功能,则被覆盖的记录的预删除操作,等于进行了一次注销,但这个效用不明显,对前端操作人员准确判断事态并对后果负责(而且可能这种注销需要额外的操作权限),不利
            bool bAppendStyle = false;  // 目标路径是否为追加形态?
            string strTargetRecId = ResPath.GetRecordId(info.NewRecPath);

            if (strTargetRecId == "?" || String.IsNullOrEmpty(strTargetRecId) == true)
                bAppendStyle = true;

            string strOutputPath = "";
            string strMetaData = "";


            if (bAppendStyle == false)
            {
                string strExistTargetXml = "";
                byte[] exist_target_timestamp = null;

                // 获取覆盖目标位置的现有记录
                lRet = channel.GetRes(info.NewRecPath,
                    out strExistTargetXml,
                    out strMetaData,
                    out exist_target_timestamp,
                    out strOutputPath,
                    out strError);
                if (lRet == -1)
                {
                    if (channel.ErrorCode == ChannelErrorCode.NotFound)
                    {
                        // 如果记录不存在, 说明不会造成覆盖态势
                        /*
                        strExistSourceXml = "<root />";
                        exist_source_timestamp = null;
                        strOutputPath = info.NewRecPath;
                         * */
                    }
                    else
                    {
                        error = new IssueInfo(info);
                        error.ErrorInfo = "move操作发生错误, 在读入即将覆盖的目标位置 '" + info.NewRecPath + "' 原有记录阶段:" + strError;
                        error.ErrorCode = channel.OriginErrorCode;
                        ErrorInfos.Add(error);
                        return -1;
                    }
                }
                else
                {
                    // 如果记录存在,则目前不允许这样的操作
                    strError = "移动(move)操作被拒绝。因为在即将覆盖的目标位置 '" + info.NewRecPath + "' 已经存在期记录。请先删除(delete)这条记录,再进行移动(move)操作";
                    goto ERROR1;
                }
            }


            string strExistSourceXml = "";
            byte[] exist_source_timestamp = null;

            // 先读出数据库中源位置的已有记录
            // REDOLOAD:

            lRet = channel.GetRes(info.OldRecPath,
                out strExistSourceXml,
                out strMetaData,
                out exist_source_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                if (channel.ErrorCode == ChannelErrorCode.NotFound)
                {
                    /*
                    // 如果记录不存在, 则构造一条空的记录
                    bExist = false;
                    strExistSourceXml = "<root />";
                    exist_source_timestamp = null;
                    strOutputPath = info.NewRecPath;
                     * */
                    // 这种情况如果放宽,会有严重的副作用,所以不让放宽
                    strError = "move操作的源记录 '" + info.OldRecPath + "' 在数据库中不存在,所以无法进行移动操作。";
                    goto ERROR1;
                }
                else
                {
                    error = new IssueInfo(info);
                    error.ErrorInfo = "保存操作发生错误, 在读入库中原有源记录(路径在info.OldRecPath) '" + info.OldRecPath + "' 阶段:" + strError;
                    error.ErrorCode = channel.OriginErrorCode;
                    ErrorInfos.Add(error);
                    return -1;
                }
            }

            // 把两个记录装入DOM

            XmlDocument domSourceExist = new XmlDocument();
            XmlDocument domNew = new XmlDocument();

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

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


            // 观察时间戳是否发生变化
            nRet = ByteArray.Compare(info.OldTimestamp, exist_source_timestamp);
            if (nRet != 0)
            {
                // 时间戳不相等了
                // 需要把info.OldRecord和strExistXml进行比较,看看和期记到有关的元素(要害元素)值是否发生了变化。
                // 如果这些要害元素并未发生变化,就继续进行合并、覆盖保存操作

                XmlDocument domOld = new XmlDocument();

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

                // 比较两个记录, 看看和期记到有关的字段是否发生了变化
                // return:
                //      0   没有变化
                //      1   有变化
                nRet = IsIssueInfoChanged(domOld,
                    domSourceExist);
                if (nRet == 1)
                {
                    error = new IssueInfo(info);
                    // 错误信息中, 返回了修改过的原记录和新时间戳
                    error.OldRecord = strExistSourceXml;
                    error.OldTimestamp = exist_source_timestamp;

                    if (bExist == false)
                        error.ErrorInfo = "保存操作发生错误: 数据库中的原记录已被删除。";
                    else
                        error.ErrorInfo = "保存操作发生错误: 数据库中的原记录已发生过修改";
                    error.ErrorCode = ErrorCodeValue.TimestampMismatch;
                    ErrorInfos.Add(error);
                    return -1;
                }

                // exist_source_timestamp此时已经反映了库中被修改后的记录的时间戳
            }


            // 合并新旧记录
            string strNewXml = "";
            nRet = MergeTwoIssueXml(domSourceExist,
                domNew,
                out strNewXml,
                out strError);
            if (nRet == -1)
                goto ERROR1;


            // 移动记录
            byte[] output_timestamp = null;

            // TODO: Copy后还要写一次?因为Copy并不写入新记录。
            // 其实Copy的意义在于带走资源。否则还不如用Save+Delete
            lRet = channel.DoCopyRecord(info.OldRecPath,
                info.NewRecPath,
                true,   // bDeleteSourceRecord
                out output_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                strError = "DoCopyRecord() error :" + strError;
                goto ERROR1;
            }

            // Debug.Assert(strOutputPath == info.NewRecPath);
            string strTargetPath = strOutputPath;

            lRet = channel.DoSaveTextRes(strTargetPath,
                strNewXml,
                false,   // include preamble?
                "content",
                output_timestamp,
                out output_timestamp,
                out strOutputPath,
                out strError);
            if (lRet == -1)
            {
                strError = "WriteIssues()API move操作中,期记录 '" + info.OldRecPath + "' 已经被成功移动到 '" + strTargetPath + "' ,但在写入新内容时发生错误: " + strError;

                if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch)
                {
                    // 不进行反复处理。
                    // 因为源已经移动,情况很复杂
                }

                // 仅仅写入错误日志即可。没有Undo
                this.WriteErrorLog(strError);

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


                error = new IssueInfo(info);
                error.ErrorInfo = "保存操作发生错误:" + strError;
                error.ErrorCode = channel.OriginErrorCode;
                ErrorInfos.Add(error);
                return -1;
            }
            else // 成功
            {
                info.NewRecPath = strOutputPath;    // 兑现保存的位置,因为可能有追加形式的路径

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

                // 新记录
                XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement,
                    "record", strNewXml);
                DomUtil.SetAttr(node, "recPath", info.NewRecPath);

                // 旧记录
                node = DomUtil.SetElementText(domOperLog.DocumentElement,
                    "oldRecord", strExistSourceXml);
                DomUtil.SetAttr(node, "recPath", info.OldRecPath);

                // 保存成功,需要返回信息元素。因为需要返回新的时间戳
                error = new IssueInfo(info);
                error.NewTimestamp = output_timestamp;
                error.NewRecord = strNewXml;

                error.ErrorInfo = "保存操作成功。NewRecPath中返回了实际保存的路径, NewTimeStamp中返回了新的时间戳,NewRecord中返回了实际保存的新记录(可能和提交的新记录稍有差异)。";
                error.ErrorCode = ErrorCodeValue.NoError;
                ErrorInfos.Add(error);
            }

            return 0;

        ERROR1:
            error = new IssueInfo(info);
            error.ErrorInfo = strError;
            error.ErrorCode = ErrorCodeValue.CommonError;
            ErrorInfos.Add(error);
            return -1;
        }
Esempio n. 3
0
        public ErrorCodeValue ErrorCode = ErrorCodeValue.NoError;   // 出错码(表示属于何种类型的错误)

        public IssueInfo(IssueInfo info)
        {
            this.OldRecPath = info.OldRecPath;
            this.OldRecord = info.OldRecord;
            this.OldTimestamp = info.OldTimestamp;
            this.NewRecPath = info.NewRecPath;
            this.NewRecord = info.NewRecord;
            this.NewTimestamp = info.NewTimestamp;
            this.Action = info.Action;
            this.ErrorInfo = info.ErrorInfo;
            this.ErrorCode = info.ErrorCode;
        }
Esempio n. 4
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;
        }
Esempio n. 5
0
        // 设置/保存期信息
        // parameters:
        //      strBiblioRecPath    书目记录路径,仅包含库名和id部分。库名可以用来确定书目库,id可以被实体记录用来设置<parent>元素内容。另外书目库名和IssueInfo中的NewRecPath形成映照关系,需要检查它们是否正确对应
        //      issueinfos 要提交的的期信息数组
        // 权限:需要有setissues权限
        // 修改意见: 写入期库中的记录, 还缺乏<operator>和<operTime>字段
        public Result SetIssues(
            SessionInfo sessioninfo,
            string strBiblioRecPath,
            IssueInfo[] issueinfos,
            out IssueInfo[] errorinfos)
        {
            errorinfos = null;

            Result result = new Result();

            // 权限字符串
            if (StringUtil.IsInList("setissueinfo", sessioninfo.RightsOrigin) == false)
            {
                result.Value = -1;
                result.ErrorInfo = "保存期信息 操作被拒绝。不具备setissueinfo权限。";
                result.ErrorCode = ErrorCode.AccessDenied;
                return result;
            }


            int nRet = 0;
            long lRet = 0;
            string strError = "";

            string strBiblioDbName = ResPath.GetDbName(strBiblioRecPath);
            string strBiblioRecId = ResPath.GetRecordId(strBiblioRecPath);

            // 获得书目库对应的期库名
            string strIssueDbName = "";
            nRet = this.GetIssueDbName(strBiblioDbName,
                 out strIssueDbName,
                 out strError);
            if (nRet == -1)
                goto ERROR1;
            if (nRet == 0)
            {
                strError = "书目库名 '" + strBiblioDbName + "' 没有找到";
                goto ERROR1;
            }
            if (String.IsNullOrEmpty(strIssueDbName) == true)
            {
                strError = "书目库名 '" + strBiblioDbName + "' 对应的期库名没有定义";
                goto ERROR1;
            }

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

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

            List<IssueInfo> ErrorInfos = new List<IssueInfo>();

            for (int i = 0; i < issueinfos.Length; i++)
            {
                IssueInfo info = issueinfos[i];

                // TODO: 当操作为"delete"时,是否可以允许只设置OldRecPath,而不必设置NewRecPath
                // 如果两个都设置,则要求设置为一致的。

                // 检查路径中的库名部分
                if (String.IsNullOrEmpty(info.NewRecPath) == false)
                {
                    strError = "";


                    string strDbName = ResPath.GetDbName(info.NewRecPath);

                    if (String.IsNullOrEmpty(strDbName) == true)
                    {
                        strError = "NewRecPath中数据库名不应为空";
                    }

                    if (strDbName != strIssueDbName)
                    {
                        strError = "RecPath中数据库名 '" + strDbName + "' 不正确,应为 '" + strIssueDbName + "'。(因为书目库名为 '" + strBiblioDbName + "',其对应的期库名应为 '" + strIssueDbName + "' )";
                    }

                    if (strError != "")
                    {
                        IssueInfo error = new IssueInfo(info);
                        error.ErrorInfo = strError;
                        error.ErrorCode = ErrorCodeValue.CommonError;
                        ErrorInfos.Add(error);
                        continue;
                    }
                }

                // 把(前端发过来的)旧记录装载到DOM
                XmlDocument domOldRec = new XmlDocument();
                try
                {
                    // 用strOldRecord的目的是不想改变info.OldRecord内容, 因为后者可能被复制到输出信息中
                    string strOldRecord = info.OldRecord;
                    if (String.IsNullOrEmpty(strOldRecord) == true)
                        strOldRecord = "<root />";

                    domOldRec.LoadXml(strOldRecord);
                }
                catch (Exception ex)
                {
                    strError = "info.OldRecord XML记录装载到DOM时出错: " + ex.Message;

                    IssueInfo error = new IssueInfo(info);
                    error.ErrorInfo = strError;
                    error.ErrorCode = ErrorCodeValue.CommonError;
                    ErrorInfos.Add(error);
                    continue;
                }

                // 把要保存的新记录装载到DOM
                XmlDocument domNewRec = new XmlDocument();
                try
                {
                    // 用strNewRecord的目的是不想改变info.NewRecord内容, 因为后者可能被复制到输出信息中
                    string strNewRecord = info.NewRecord;

                    if (String.IsNullOrEmpty(strNewRecord) == true)
                        strNewRecord = "<root />";

                    domNewRec.LoadXml(strNewRecord);
                }
                catch (Exception ex)
                {
                    strError = "info.NewRecord XML记录装载到DOM时出错: " + ex.Message;

                    IssueInfo error = new IssueInfo(info);
                    error.ErrorInfo = strError;
                    error.ErrorCode = ErrorCodeValue.CommonError;
                    ErrorInfos.Add(error);
                    continue;
                }

                string strOldPublishTime = "";
                string strNewPublishTime = "";

                string strOldParentID = "";
                string strNewParentID = "";

                // 对出版时间加锁?
                string strLockPublishTime = "";

                try
                {


                    // 命令new和change的共有部分 -- 出版时间查重, 也需要加锁
                    // delete则需要加锁
                    if (info.Action == "new"
                        || info.Action == "change"
                        || info.Action == "delete"
                        || info.Action == "move")
                    {

                        // 仅仅用来获取一下新出版时间
                        // 看看新旧出版时间是否有差异
                        // 对IssueInfo中的OldRecord和NewRecord中包含的条码号进行比较, 看看是否发生了变化(进而就需要查重)
                        // return:
                        //      -1  出错
                        //      0   相等
                        //      1   不相等
                        nRet = CompareTwoIssueNo(domOldRec,
                            domNewRec,
                            out strOldPublishTime,
                            out strOldParentID,
                            out strNewPublishTime,
                            out strNewParentID,
                            out strError);
                        if (nRet == -1)
                        {
                            strError = "CompareTwoIssueNo() error : " + strError;
                            goto ERROR1;
                        }

                        if (info.Action == "new"
                            || info.Action == "change"
                            || info.Action == "move")
                            strLockPublishTime = strNewPublishTime;
                        else if (info.Action == "delete")
                        {
                            // 顺便进行一些检查
                            if (String.IsNullOrEmpty(strNewPublishTime) == false)
                            {
                                strError = "没有必要在delete操作的IssueInfo中, 包含NewRecord内容...。相反,注意一定要在OldRecord中包含即将删除的原记录";
                                goto ERROR1;
                            }
                            strLockPublishTime = strOldPublishTime;
                        }


                        // 加锁
                        if (String.IsNullOrEmpty(strLockPublishTime) == false)
                            this.EntityLocks.LockForWrite(strLockPublishTime);

                        // 进行出版时间查重
                        // TODO: 查重的时候要注意,如果操作类型为“move”,则可以允许查出和info.OldRecPath重的,因为它即将被删除
                        if (nRet == 1   // 新旧出版时间不等,才查重。这样可以提高运行效率。
                            && (info.Action == "new"
                                || info.Action == "change"
                                || info.Action == "move")       // delete操作不查重
                            && String.IsNullOrEmpty(strNewPublishTime) == false
                            )
                        {
                            string strParentID = strNewParentID;

                            if (String.IsNullOrEmpty(strParentID) == true)
                                strParentID = strOldParentID;

                            List<string> aPath = null;
                            // 根据 父记录ID+出版时间 对期库进行查重
                            // 本函数只负责查重, 并不获得记录体
                            // return:
                            //      -1  error
                            //      其他    命中记录条数(不超过nMax规定的极限)
                            nRet = SearchIssueRecDup(
                                sessioninfo.Channels,
                                strIssueDbName,
                                strParentID,
                                strNewPublishTime,
                                100,
                                out aPath,
                                out strError);
                            if (nRet == -1)
                                goto ERROR1;

                            bool bDup = false;
                            if (nRet == 0)
                            {
                                bDup = false;
                            }
                            else if (nRet == 1) // 命中一条
                            {
                                Debug.Assert(aPath.Count == 1, "");

                                if (info.Action == "new")
                                {
                                    if (aPath[0] == info.NewRecPath) // 正好是自己
                                        bDup = false;
                                    else
                                        bDup = true;// 别的记录中已经使用了这个条码号

                                }
                                else if (info.Action == "change")
                                {
                                    Debug.Assert(info.NewRecPath == info.OldRecPath, "当操作类型为change时,info.NewRecPath应当和info.OldRecPath相同");
                                    if (aPath[0] == info.OldRecPath) // 正好是自己
                                        bDup = false;
                                    else
                                        bDup = true;// 别的记录中已经使用了这个条码号
                                }
                                else if (info.Action == "move")
                                {
                                    if (aPath[0] == info.OldRecPath) // 正好是源记录
                                        bDup = false;
                                    else
                                        bDup = true;// 别的记录中已经使用了这个条码号
                                }
                                else
                                {
                                    Debug.Assert(false, "这里不可能出现的info.Action值 '" + info.Action + "'");
                                }


                            } // end of if (nRet == 1)
                            else
                            {
                                Debug.Assert(nRet > 1, "");
                                bDup = true;

                                // 因为move操作不允许目标位置存在记录,所以这里就不再费力考虑了
                                // 如果将来move操作允许目标位置存在记录,则这里需要判断:无论源还是目标位置发现条码号重,都不算重。
                            }

                            // 报错
                            if (bDup == true)
                            {
                                string[] pathlist = new string[aPath.Count];
                                aPath.CopyTo(pathlist);

                                IssueInfo error = new IssueInfo(info);
                                error.ErrorInfo = "出版时间 '" + strNewPublishTime + "' 已经被下列期记录使用了: " + String.Join(",", pathlist);
                                error.ErrorCode = ErrorCodeValue.CommonError;
                                ErrorInfos.Add(error);
                                continue;
                            }
                        }
                    }

                    // 准备日志DOM
                    XmlDocument domOperLog = new XmlDocument();
                    domOperLog.LoadXml("<root />");
                    DomUtil.SetElementText(domOperLog.DocumentElement, "operation", "setIssue");

                    // 兑现一个命令
                    if (info.Action == "new")
                    {
                        // 检查新记录的路径中的id部分是否正确
                        // 库名部分,前面已经统一检查过了
                        strError = "";

                        if (String.IsNullOrEmpty(info.NewRecPath) == true)
                        {
                            info.NewRecPath = strIssueDbName + "/?";
                        }
                        else
                        {

                            string strID = ResPath.GetRecordId(info.NewRecPath);
                            if (String.IsNullOrEmpty(strID) == true)
                            {
                                strError = "RecPath中id部分应当为'?'";
                            }

                            if (strError != "")
                            {
                                IssueInfo error = new IssueInfo(info);
                                error.ErrorInfo = strError;
                                error.ErrorCode = ErrorCodeValue.CommonError;
                                ErrorInfos.Add(error);
                                continue;
                            }
                        }

                        // 构造出适合保存的新期记录
                        string strNewXml = "";
                        nRet = BuildNewIssueRecord(info.NewRecord,
                            out strNewXml,
                            out strError);
                        if (nRet == -1)
                        {
                            IssueInfo error = new IssueInfo(info);
                            error.ErrorInfo = strError;
                            error.ErrorCode = ErrorCodeValue.CommonError;
                            ErrorInfos.Add(error);
                            continue;
                        }

                        lRet = channel.DoSaveTextRes(info.NewRecPath,
                            strNewXml,
                            false,   // include preamble?
                            "content",
                            info.OldTimestamp,
                            out output_timestamp,
                            out strOutputPath,
                            out strError);
                        if (lRet == -1)
                        {
                            IssueInfo error = new IssueInfo(info);
                            error.NewTimestamp = output_timestamp;
                            error.ErrorInfo = "保存新记录的操作发生错误:" + strError;
                            error.ErrorCode = channel.OriginErrorCode;
                            ErrorInfos.Add(error);

                            domOperLog = null;  // 表示不必写入日志
                        }
                        else // 成功
                        {

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

                            // 不创建<oldRecord>元素

                            XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement,
                                "record", strNewXml);
                            DomUtil.SetAttr(node, "recPath", strOutputPath);

                            // 新记录保存成功,需要返回信息元素。因为需要返回新的时间戳和实际保存的记录路径

                            IssueInfo error = new IssueInfo(info);
                            error.NewRecPath = strOutputPath;

                            error.NewRecord = strNewXml;    // 所真正保存的记录,可能稍有变化, 因此需要返回给前端
                            error.NewTimestamp = output_timestamp;

                            error.ErrorInfo = "保存新记录的操作成功。NewTimeStamp中返回了新的时间戳, RecPath中返回了实际存入的记录路径。";
                            error.ErrorCode = ErrorCodeValue.NoError;
                            ErrorInfos.Add(error);
                        }
                    }
                    else if (info.Action == "change")
                    {
                        // 执行SetIssues API中的"change"操作
                        nRet = DoIssueOperChange(
                            channel,
                            info,
                            ref domOperLog,
                            ref ErrorInfos);
                        if (nRet == -1)
                        {
                            // 失败
                            domOperLog = null;  // 表示不必写入日志
                        }
                    }
                    else if (info.Action == "move")
                    {
                        // 执行SetIssues API中的"move"操作
                        nRet = DoIssueOperMove(
                            channel,
                            info,
                            ref domOperLog,
                            ref ErrorInfos);
                        if (nRet == -1)
                        {
                            // 失败
                            domOperLog = null;  // 表示不必写入日志
                        }
                    }
                    else if (info.Action == "delete")
                    {
                        string strParentID = strNewParentID;

                        if (String.IsNullOrEmpty(strParentID) == true)
                            strParentID = strOldParentID;


                        // 删除期记录的操作
                        nRet = DoIssueOperDelete(
                            sessioninfo,
                            channel,
                            info,
                            strIssueDbName,
                            strParentID,
                            strOldPublishTime,
                            strNewPublishTime,
                            domOldRec,
                            ref domOperLog,
                            ref ErrorInfos);
                        if (nRet == -1)
                        {
                            // 失败
                            domOperLog = null;  // 表示不必写入日志
                        }
                    }
                    else
                    {
                        // 不支持的命令
                        IssueInfo error = new IssueInfo(info);
                        error.ErrorInfo = "不支持的操作命令 '" + info.Action + "'";
                        error.ErrorCode = ErrorCodeValue.CommonError;
                        ErrorInfos.Add(error);
                    }


                    // 写入日志
                    if (domOperLog != null)
                    {
                        string strOperTime = this.Clock.GetClock();
                        DomUtil.SetElementText(domOperLog.DocumentElement, "operator",
                            sessioninfo.UserID);   // 操作者
                        DomUtil.SetElementText(domOperLog.DocumentElement, "operTime",
                            strOperTime);   // 操作时间

                        nRet = this.OperLog.WriteOperLog(domOperLog,
                            out strError);
                        if (nRet == -1)
                        {
                            strError = "SetIssues() API 写入日志时发生错误: " + strError;
                            goto ERROR1;
                        }
                    }
                }
                finally
                {
                    if (String.IsNullOrEmpty(strLockPublishTime) == false)
                        this.EntityLocks.UnlockForWrite(strLockPublishTime);
                }

            }

            // 复制到结果中
            errorinfos = new IssueInfo[ErrorInfos.Count];
            for (int i = 0; i < ErrorInfos.Count; i++)
            {
                errorinfos[i] = ErrorInfos[i];
            }

            result.Value = ErrorInfos.Count;  // 返回信息的数量

            return result;
        ERROR1:
            // 这里的报错,是比较严重的错误。如果是数组中部分的请求发生的错误,则不在这里报错,而是通过返回错误信息数组的方式来表现
            result.Value = -1;
            result.ErrorInfo = strError;
            result.ErrorCode = ErrorCode.SystemError;
            return result;
        }
Esempio n. 6
0
        // TODO: 需要有限定期范围的能力
        // 获得期信息
        // parameters:
        //      strBiblioRecPath    书目记录路径,仅包含库名和id部分
        //      issues 返回的期信息数组
        // 权限:需要有getissues权限
        // return:
        //      Result.Value    -1出错 0没有找到 其他 实体记录的个数
        public Result GetIssues(
            SessionInfo sessioninfo,
            string strBiblioRecPath,
            out IssueInfo[] issues)
        {

            issues = null;

            Result result = new Result();

            // 权限字符串
            if (StringUtil.IsInList("getissues", sessioninfo.RightsOrigin) == false
        && StringUtil.IsInList("getissueinfo", sessioninfo.RightsOrigin) == false)
            {
                result.Value = -1;
                result.ErrorInfo = "获得期信息 操作被拒绝。不具备getissueinfo或getissues权限。";
                result.ErrorCode = ErrorCode.AccessDenied;
                return result;
            }


            int nRet = 0;
            string strError = "";

            string strBiblioDbName = ResPath.GetDbName(strBiblioRecPath);
            string strBiblioRecId = ResPath.GetRecordId(strBiblioRecPath);

            // 获得书目库对应的期库名
            string strIssueDbName = "";
            nRet = this.GetIssueDbName(strBiblioDbName,
                 out strIssueDbName,
                 out strError);
            if (nRet == -1)
                goto ERROR1;
            if (nRet == 0)
            {
                strError = "书目库名 '" + strBiblioDbName + "' 没有找到";
                goto ERROR1;
            }
            if (String.IsNullOrEmpty(strIssueDbName) == true)
            {
                strError = "书目库名 '" +strBiblioDbName+ "' 对应的期库名没有定义";
                goto ERROR1;
            }

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

            // 检索期库中全部从属于特定id的记录

            string strQueryXml = "<target list='"
                + StringUtil.GetXmlStringSimple(strIssueDbName + ":" + "父记录")       // 2007/9/14
                + "'><item><word>"
                + strBiblioRecId
                + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>" + "zh" + "</lang></target>";
            long lRet = channel.DoSearch(strQueryXml,
                "issues",
                out strError);
            if (lRet == -1)
                goto ERROR1;

            if (lRet == 0)
            {
                result.Value = 0;
                result.ErrorInfo = "没有找到";
                return result;
            }

            int nResultCount = (int)lRet;

            if (nResultCount > 10000)
            {
                strError = "命中期记录数 " + nResultCount.ToString() + " 超过 10000, 暂时不支持";
                goto ERROR1;
            }

            List<IssueInfo> issueinfos = new List<IssueInfo>();

            int nStart = 0;
            int nPerCount = 100;
            for (; ; )
            {
                List<string> aPath = null;
                lRet = channel.DoGetSearchResult(
                    "issues",
                    nStart,
                    nPerCount,
                    "zh",
                    null,
                    out aPath,
                    out strError);
                if (lRet == -1)
                    goto ERROR1;

                if (aPath.Count == 0)
                {
                    strError = "aPath.Count == 0";
                    goto ERROR1;
                }

                // 获得每条记录
                for (int i = 0; i < aPath.Count; i++)
                {
                    string strMetaData = "";
                    string strXml = "";
                    byte[] timestamp = null;
                    string strOutputPath = "";

                    lRet = channel.GetRes(aPath[i],
                        out strXml,
                        out strMetaData,
                        out timestamp,
                        out strOutputPath,
                        out strError);
                    IssueInfo issueinfo = new IssueInfo();

                    if (lRet == -1)
                    {
                        issueinfo.OldRecPath = aPath[i];
                        issueinfo.ErrorCode = channel.OriginErrorCode;
                        issueinfo.ErrorInfo = channel.ErrorInfo;

                        issueinfo.OldRecord = "";
                        issueinfo.OldTimestamp = null;

                        issueinfo.NewRecPath = "";
                        issueinfo.NewRecord = "";
                        issueinfo.NewTimestamp = null;
                        issueinfo.Action = "";


                        goto CONTINUE;
                    }

                    issueinfo.OldRecPath = strOutputPath;
                    issueinfo.OldRecord = strXml;
                    issueinfo.OldTimestamp = timestamp;

                    issueinfo.NewRecPath = "";
                    issueinfo.NewRecord = "";
                    issueinfo.NewTimestamp = null;
                    issueinfo.Action = "";

                CONTINUE:
                    issueinfos.Add(issueinfo);
                }

                nStart += aPath.Count;
                if (nStart >= nResultCount)
                    break;
            }

            // 挂接到结果中
            issues = new IssueInfo[issueinfos.Count];
            for (int i = 0; i < issueinfos.Count; i++)
            {
                issues[i] = issueinfos[i];
            }

            result.Value = issues.Length;
            return result;

        ERROR1:
            result.Value = -1;
            result.ErrorInfo = strError;
            result.ErrorCode = ErrorCode.SystemError;
            return result;
        }