Beispiel #1
0
        public void LoadRules()
        {
            var criteria = new ServerRuleSelectCriteria();

            // only query for rule in this partition
            criteria.ServerPartitionKey.EqualTo(ServerPartition.GetKey());
            criteria.ServerRuleTypeEnum.EqualTo(ServerRuleTypeEnum.DataAccess);

            if (StatusFilter.SelectedIndex != 0)
            {
                if (StatusFilter.SelectedIndex == 1)
                {
                    criteria.Enabled.EqualTo(true);
                }
                else
                {
                    criteria.Enabled.EqualTo(false);
                }
            }

            if (DefaultFilter.SelectedIndex != 0)
            {
                if (DefaultFilter.SelectedIndex == 1)
                {
                    criteria.DefaultRule.EqualTo(true);
                }
                else
                {
                    criteria.DefaultRule.EqualTo(false);
                }
            }

            DataRuleGridViewControl.DataRules = _controller.GetServerRules(criteria);
            DataRuleGridViewControl.DataBind();
        }
Beispiel #2
0
        /// <summary>
        /// Checks for a storage location for the study in the database, and creates a new location
        /// in the database if it doesn't exist.
        /// </summary>
        /// <param name="partition">The partition where the study is being sent to</param>
        /// <param name="created"></param>
        /// <param name="studyDate"></param>
        /// <param name="studyInstanceUid"></param>
        /// <param name="syntax"></param>
        /// <param name="updateContext">The update context to create the study on</param>
        /// <returns>A <see cref="StudyStorageLocation"/> instance.</returns>
        public StudyStorageLocation GetOrCreateWritableStudyStorageLocation(string studyInstanceUid, string studyDate, TransferSyntax syntax, IUpdateContext updateContext, ServerPartition partition, out bool created)
        {
            created = false;

            StudyStorageLocation location;

            try
            {
                GetWritableStudyStorageLocation(partition.Key, studyInstanceUid, StudyRestore.True,
                                                StudyCache.True, out location);
                return(location);
            }
            catch (StudyNotFoundException)
            {
            }

            FilesystemSelector   selector   = new FilesystemSelector(Instance);
            ServerFilesystemInfo filesystem = selector.SelectFilesystem();

            if (filesystem == null)
            {
                throw new NoWritableFilesystemException();
            }

            IInsertStudyStorage          locInsert   = updateContext.GetBroker <IInsertStudyStorage>();
            InsertStudyStorageParameters insertParms = new InsertStudyStorageParameters
            {
                ServerPartitionKey = partition.GetKey(),
                StudyInstanceUid   = studyInstanceUid,
                Folder             =
                    ResolveStorageFolder(partition.Key, studyInstanceUid, studyDate,
                                         updateContext, false
                                         /* set to false for optimization because we are sure it's not in the system */),
                FilesystemKey       = filesystem.Filesystem.GetKey(),
                QueueStudyStateEnum = QueueStudyStateEnum.Idle
            };

            if (syntax.LosslessCompressed)
            {
                insertParms.TransferSyntaxUid = syntax.UidString;
                insertParms.StudyStatusEnum   = StudyStatusEnum.OnlineLossless;
            }
            else if (syntax.LossyCompressed)
            {
                insertParms.TransferSyntaxUid = syntax.UidString;
                insertParms.StudyStatusEnum   = StudyStatusEnum.OnlineLossy;
            }
            else
            {
                insertParms.TransferSyntaxUid = syntax.UidString;
                insertParms.StudyStatusEnum   = StudyStatusEnum.Online;
            }

            location = locInsert.FindOne(insertParms);
            created  = true;

            return(location);
        }
Beispiel #3
0
        /// <summary>
        /// Load the devices for the partition based on the filters specified in the filter panel.
        /// </summary>
        /// <remarks>
        /// This method only reloads and binds the list bind to the internal grid. <seealso cref="Refresh"/> should be called
        /// to explicit update the list in the grid.
        /// <para>
        /// This is intentionally so that the list can be reloaded so that it is available to other controls during postback.  In
        /// some cases we may not want to refresh the list if there's no change. Calling <seealso cref="Refresh"/> will
        /// give performance hit as the data will be transfered back to the browser.
        ///
        /// </para>
        /// </remarks>
        public void LoadDevices()
        {
            if (ServerPartition == null)
            {
                return;
            }

            var criteria = new DeviceSelectCriteria();

            // only query for device in this partition
            criteria.ServerPartitionKey.EqualTo(ServerPartition.GetKey());

            if (!String.IsNullOrEmpty(AETitleFilter.TrimText))
            {
                QueryHelper.SetGuiStringCondition(criteria.AeTitle,
                                                  SearchHelper.LeadingAndTrailingWildCard(AETitleFilter.TrimText));
            }

            if (!String.IsNullOrEmpty(DescriptionFilter.TrimText))
            {
                QueryHelper.SetGuiStringCondition(criteria.Description,
                                                  SearchHelper.LeadingAndTrailingWildCard(DescriptionFilter.TrimText));
            }

            if (!String.IsNullOrEmpty(IPAddressFilter.TrimText))
            {
                QueryHelper.SetGuiStringCondition(criteria.IpAddress,
                                                  SearchHelper.TrailingWildCard(IPAddressFilter.TrimText));
            }

            if (StatusFilter.SelectedIndex != 0)
            {
                criteria.Enabled.EqualTo(StatusFilter.SelectedIndex == 1);
            }

            if (DHCPFilter.SelectedIndex != 0)
            {
                criteria.Dhcp.EqualTo(DHCPFilter.SelectedIndex == 1);
            }

            if (DeviceTypeFilter.SelectedIndex > -1)
            {
                var types = new List <DeviceTypeEnum>();
                foreach (ListItem item in DeviceTypeFilter.Items)
                {
                    if (item.Selected)
                    {
                        types.Add(DeviceTypeEnum.GetEnum(item.Value));
                    }
                }
                criteria.DeviceTypeEnum.In(types);
            }

            DeviceGridViewControl1.Devices = _theController.GetDevices(criteria);
            DeviceGridViewControl1.RefreshCurrentPage();
        }
        /// <summary>
        /// Update the specified partition tab
        /// </summary>
        /// <param name="tabIndex">The server partition tab index</param>
        /// <remarks>
        ///
        /// </remarks>
        public void Update(int tabIndex)
        {
            if (_partitionList == null || _partitionList.Count == 0)
            {
                return;
            }

            ServerPartition partition = _partitionList[tabIndex];

            Update(partition.GetKey());
        }
Beispiel #5
0
        private static StudyStorageLocation FindStudyStorageLocation(IUpdateContext context, ServerPartition partition, string studyInstanceUid)
        {
            var procedure = context.GetBroker <IQueryStudyStorageLocation>();
            var parms     = new StudyStorageLocationQueryParameters
            {
                ServerPartitionKey = partition.GetKey(),
                StudyInstanceUid   = studyInstanceUid
            };

            return(procedure.FindOne(parms));
        }
Beispiel #6
0
        private IList <PartitionSopClass> LoadPartitionSopClassesFromDatabase(ServerPartition partition)
        {
            using (IReadContext context = PersistentStoreRegistry.GetDefaultStore().OpenReadContext())
            {
                // Set the input parameters for query
                var inputParms = new PartitionSopClassQueryParameters {
                    ServerPartitionKey = partition.GetKey()
                };

                var broker = context.GetBroker <IQueryServerPartitionSopClasses>();
                return(broker.Find(inputParms));
            }
        }
        public void LoadRules()
        {
            var criteria = new ServerRuleSelectCriteria();

            // only query for device in this partition
            criteria.ServerPartitionKey.EqualTo(ServerPartition.GetKey());

            if (!String.IsNullOrEmpty(RuleApplyTimeDropDownList.Text))
            {
                if (!RuleApplyTimeDropDownList.SelectedValue.Equals("ALL"))
                {
                    ServerRuleApplyTimeEnum en =
                        ServerRuleApplyTimeEnum.GetEnum(RuleApplyTimeDropDownList.SelectedItem.Value);
                    criteria.ServerRuleApplyTimeEnum.EqualTo(en);
                }
            }
            if (!String.IsNullOrEmpty(RuleTypeDropDownList.Text))
            {
                if (!RuleTypeDropDownList.SelectedValue.Equals("ALL"))
                {
                    ServerRuleTypeEnum en = ServerRuleTypeEnum.GetEnum(RuleTypeDropDownList.SelectedItem.Value);
                    criteria.ServerRuleTypeEnum.EqualTo(en);
                }
                else
                {
                    criteria.ServerRuleTypeEnum.NotEqualTo(ServerRuleTypeEnum.DataAccess);
                }
            }
            else
            {
                criteria.ServerRuleTypeEnum.NotEqualTo(ServerRuleTypeEnum.DataAccess);
            }

            if (StatusFilter.SelectedIndex != 0)
            {
                criteria.Enabled.EqualTo(StatusFilter.SelectedIndex == 1);
            }

            if (DefaultFilter.SelectedIndex != 0)
            {
                criteria.DefaultRule.EqualTo(DefaultFilter.SelectedIndex == 1);
            }

            ServerRuleGridViewControl.ServerRules = _controller.GetServerRules(criteria);
            ServerRuleGridViewControl.DataBind();
        }
        /// <summary>
        /// Apply the Rules engine.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method applies the rules engine to the first image in each series within a study.
        /// The assumption is that the actions generated by the engine can handle being applied more
        /// than once for the same study.  This is also done to handle the case of multi-modality
        /// studies where you may want the rules to be run against each series, because they may
        /// apply differently.
        /// </para>
        /// <para>
        /// Note that we are still applying series level moves, although there currently are not
        /// any series level rules.  We've somewhat turned the study level rules into series
        /// level rules.
        /// </para>
        /// </remarks>
        public void Apply(ServerRuleApplyTimeEnum applyTime)
        {
            using (var theProcessor = new ServerCommandProcessor("Study Rule Processor")
            {
                PrimaryServerPartitionKey = _partition.GetKey(),
                PrimaryStudyKey = _location.Study.GetKey()
            })
            {
                Apply(applyTime, theProcessor);

                if (false == theProcessor.Execute())
                {
                    Platform.Log(LogLevel.Error,
                                 "Unexpected failure processing Study level rules for study {0} on partition {1} for {2} apply time",
                                 _location.StudyInstanceUid, _partition.Description, applyTime.Description);
                }
            }
        }
Beispiel #9
0
        /// <summary>
        /// Load <see cref="Device"/> information for a Move destination.
        /// </summary>
        /// <param name="read"></param>
        /// <param name="partition"></param>
        /// <param name="remoteAe"></param>
        /// <returns></returns>
        private static Device LoadRemoteHost(IPersistenceContext read, ServerPartition partition, string remoteAe)
        {
            var select = read.GetBroker <IDeviceEntityBroker>();

            // Setup the select parameters.
            var selectParms = new DeviceSelectCriteria();

            selectParms.AeTitle.EqualTo(remoteAe);
            selectParms.ServerPartitionKey.EqualTo(partition.GetKey());
            var devices = select.Find(selectParms);

            foreach (var d in devices)
            {
                if (string.Compare(d.AeTitle, remoteAe, false, CultureInfo.InvariantCulture) == 0)
                {
                    return(d);
                }
            }
            return(null);
        }
Beispiel #10
0
        /// <summary>
        /// Reprocess a specific study.
        /// </summary>
        /// <param name="partition">The ServerPartition the study is on.</param>
        /// <param name="location">The storage location of the study to process.</param>
        /// <param name="engine">The rules engine to use when processing the study.</param>
        /// <param name="postArchivalEngine">The rules engine used for studies that have been archived.</param>
        /// <param name="dataAccessEngine">The rules engine strictly used for setting data acess.</param>
        protected static void ProcessStudy(ServerPartition partition, StudyStorageLocation location, ServerRulesEngine engine, ServerRulesEngine postArchivalEngine, ServerRulesEngine dataAccessEngine)
        {
            if (!location.QueueStudyStateEnum.Equals(QueueStudyStateEnum.Idle) || !location.AcquireWriteLock())
            {
                Platform.Log(LogLevel.Error, "Unable to lock study {0}. The study is being processed. (Queue State: {1})", location.StudyInstanceUid, location.QueueStudyStateEnum.Description);
            }
            else
            {
                try
                {
                    DicomFile msg = LoadInstance(location);
                    if (msg == null)
                    {
                        Platform.Log(LogLevel.Error, "Unable to load file for study {0}", location.StudyInstanceUid);
                        return;
                    }

                    bool archiveQueueExists;
                    bool archiveStudyStorageExists;
                    bool filesystemDeleteExists;
                    using (IReadContext read = PersistentStoreRegistry.GetDefaultStore().OpenReadContext())
                    {
                        // Check for existing archive queue entries
                        var archiveQueueBroker   = read.GetBroker <IArchiveQueueEntityBroker>();
                        var archiveQueueCriteria = new ArchiveQueueSelectCriteria();
                        archiveQueueCriteria.StudyStorageKey.EqualTo(location.Key);
                        archiveQueueExists = archiveQueueBroker.Count(archiveQueueCriteria) > 0;


                        var archiveStorageBroker        = read.GetBroker <IArchiveStudyStorageEntityBroker>();
                        var archiveStudyStorageCriteria = new ArchiveStudyStorageSelectCriteria();
                        archiveStudyStorageCriteria.StudyStorageKey.EqualTo(location.Key);
                        archiveStudyStorageExists = archiveStorageBroker.Count(archiveStudyStorageCriteria) > 0;

                        var filesystemQueueBroker   = read.GetBroker <IFilesystemQueueEntityBroker>();
                        var filesystemQueueCriteria = new FilesystemQueueSelectCriteria();
                        filesystemQueueCriteria.StudyStorageKey.EqualTo(location.Key);
                        filesystemQueueCriteria.FilesystemQueueTypeEnum.EqualTo(FilesystemQueueTypeEnum.DeleteStudy);
                        filesystemDeleteExists = filesystemQueueBroker.Count(filesystemQueueCriteria) > 0;
                    }

                    using (var commandProcessor = new ServerCommandProcessor("Study Rule Processor")
                    {
                        PrimaryServerPartitionKey = partition.GetKey(),
                        PrimaryStudyKey = location.Study.GetKey()
                    })
                    {
                        var context = new ServerActionContext(msg, location.FilesystemKey, partition, location.Key, commandProcessor);

                        // Check if the Study has been archived
                        if (archiveStudyStorageExists && !archiveQueueExists && !filesystemDeleteExists)
                        {
                            // Add a command to delete the current filesystemQueue entries, so that they can
                            // be reinserted by the rules engine.
                            context.CommandProcessor.AddCommand(new DeleteFilesystemQueueCommand(location.Key, ServerRuleApplyTimeEnum.StudyArchived));

                            // How to deal with exiting FilesystemQueue entries is problematic here.  If the study
                            // has been migrated off tier 1, we probably don't want to modify the tier migration
                            // entries.  Compression entries may have been entered when the Study was initially
                            // processed, we don't want to delete them, because they might still be valid.
                            // We just re-run the rules engine at this point, and delete only the StudyPurge entries,
                            // since those we know at least would only be applied for archived studies.
                            var studyRulesEngine = new StudyRulesEngine(postArchivalEngine, location, location.ServerPartition, location.LoadStudyXml());
                            studyRulesEngine.Apply(ServerRuleApplyTimeEnum.StudyArchived, commandProcessor);

                            // Post Archive doesn't allow data access rules.  Force Data Access rules to be reapplied
                            // to these studies also.
                            dataAccessEngine.Execute(context);
                        }
                        else
                        {
                            // Add a command to delete the current filesystemQueue entries, so that they can
                            // be reinserted by the rules engine.
                            context.CommandProcessor.AddCommand(new DeleteFilesystemQueueCommand(location.Key, ServerRuleApplyTimeEnum.StudyProcessed));

                            // Execute the rules engine, insert commands to update the database into the command processor.
                            // Due to ticket #11673, we create a new rules engine instance for each study, since the Study QC rules
                            // don't work right now with a single rules engine.
                            //TODO CR (Jan 2014) - Check if we can go back to caching the rules engine to reduce database hits on the rules
                            var studyRulesEngine = new StudyRulesEngine(location, location.ServerPartition, location.LoadStudyXml());
                            studyRulesEngine.Apply(ServerRuleApplyTimeEnum.StudyProcessed, commandProcessor);
                        }

                        // Do the actual database updates.
                        if (false == context.CommandProcessor.Execute())
                        {
                            Platform.Log(LogLevel.Error, "Unexpected failure processing Study level rules for study {0}", location.StudyInstanceUid);
                        }

                        // Log the FilesystemQueue related entries
                        location.LogFilesystemQueue();
                    }
                }
                finally
                {
                    location.ReleaseWriteLock();
                }
            }
        }
Beispiel #11
0
        /// <summary>
        /// Lookup the device entity in the database corresponding to the remote AE of the association.
        /// </summary>
        /// <param name="partition">The partition to look up the devices</param>
        /// <param name="association">The association</param>
        /// <param name="isNew">Indicates whether the device returned is created by the call.</param>
        /// <returns>The device record corresponding to the called AE of the association</returns>
        public static Device LookupDevice(ServerPartition partition, AssociationParameters association, out bool isNew)
        {
            isNew = false;

            Device device;

            if (DeviceCache.TryGetValue(association.CallingAE + partition.Key, out device))
            {
                return(device);
            }

            using (
                IUpdateContext updateContext =
                    PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
            {
                var deviceEntityBroker = updateContext.GetBroker <IDeviceEntityBroker>();

                // Setup the select parameters.
                var queryParameters = new DeviceSelectCriteria();
                queryParameters.AeTitle.EqualTo(association.CallingAE);
                queryParameters.ServerPartitionKey.EqualTo(partition.GetKey());
                var devices = deviceEntityBroker.Find(queryParameters);
                foreach (var d in devices)
                {
                    if (string.Compare(d.AeTitle, association.CallingAE, false, CultureInfo.InvariantCulture) == 0)
                    {
                        device = d;
                        break;
                    }
                }

                if (device == null)
                {
                    if (!partition.AcceptAnyDevice)
                    {
                        return(null);
                    }

                    if (partition.AutoInsertDevice)
                    {
                        // Auto-insert a new entry in the table.
                        var updateColumns = new DeviceUpdateColumns
                        {
                            AeTitle                = association.CallingAE,
                            Enabled                = true,
                            Description            = String.Format("AE: {0}", association.CallingAE),
                            Dhcp                   = false,
                            IpAddress              = association.RemoteEndPoint.Address.ToString(),
                            ServerPartitionKey     = partition.GetKey(),
                            Port                   = partition.DefaultRemotePort,
                            AllowQuery             = true,
                            AllowRetrieve          = true,
                            AllowStorage           = true,
                            ThrottleMaxConnections = ImageServerCommonConfiguration.Device.MaxConnections,
                            DeviceTypeEnum         = DeviceTypeEnum.Workstation
                        };

                        var insert = updateContext.GetBroker <IDeviceEntityBroker>();

                        device = insert.Insert(updateColumns);

                        updateContext.Commit();

                        isNew = true;
                    }
                }

                if (device != null)
                {
                    // For DHCP devices, we always update the remote ip address, if its changed from what is in the DB.
                    if (device.Dhcp && !association.RemoteEndPoint.Address.ToString().Equals(device.IpAddress))
                    {
                        var updateColumns = new DeviceUpdateColumns
                        {
                            IpAddress        = association.RemoteEndPoint.Address.ToString(),
                            LastAccessedTime = Platform.Time
                        };

                        if (!deviceEntityBroker.Update(device.GetKey(), updateColumns))
                        {
                            Platform.Log(LogLevel.Error,
                                         "Unable to update IP Address for DHCP device {0} on partition '{1}'",
                                         device.AeTitle, partition.Description);
                        }
                        else
                        {
                            updateContext.Commit();
                        }
                    }
                    else if (!isNew)
                    {
                        var updateColumns = new DeviceUpdateColumns {
                            LastAccessedTime = Platform.Time
                        };

                        if (!deviceEntityBroker.Update(device.GetKey(), updateColumns))
                        {
                            Platform.Log(LogLevel.Error,
                                         "Unable to update LastAccessedTime device {0} on partition '{1}'",
                                         device.AeTitle, partition.Description);
                        }
                        else
                        {
                            updateContext.Commit();
                        }
                    }

                    DeviceCache.Add(device.AeTitle + partition.Key, device);
                }
            }

            return(device);
        }
        /// <summary>
        /// Reprocess a file systems
        /// </summary>
        /// <param name="partition"></param>
        private void ReprocessPartition(ServerPartition partition)
        {
            var engine = new ServerRulesEngine(ServerRuleApplyTimeEnum.StudyProcessed, partition.Key);

            engine.Load();

            var postArchivalEngine = new ServerRulesEngine(ServerRuleApplyTimeEnum.StudyArchived, partition.Key);

            postArchivalEngine.Load();

            var dataAccessEngine = new ServerRulesEngine(ServerRuleApplyTimeEnum.StudyProcessed, partition.Key);

            dataAccessEngine.AddIncludeType(ServerRuleTypeEnum.DataAccess);
            dataAccessEngine.Load();

            var filesystems = FilesystemMonitor.Instance.GetFilesystems();

            foreach (var f in filesystems)
            {
                var partitionDir  = Path.Combine(f.Filesystem.FilesystemPath, partition.PartitionFolder);
                var filesystemDir = new DirectoryInfo(partitionDir);
                foreach (DirectoryInfo dateDir in filesystemDir.GetDirectories())
                {
                    if (dateDir.FullName.EndsWith("Deleted") ||
                        dateDir.FullName.EndsWith(ServerPlatform.ReconcileStorageFolder))
                    {
                        continue;
                    }

                    foreach (DirectoryInfo studyDir in dateDir.GetDirectories())
                    {
                        String studyInstanceUid = studyDir.Name;
                        try
                        {
                            StudyStorageLocation location = LoadReadableStorageLocation(partition.GetKey(), studyInstanceUid);
                            if (location == null)
                            {
                                foreach (DirectoryInfo seriesDir in studyDir.GetDirectories())
                                {
                                    FileInfo[] sopInstanceFiles = seriesDir.GetFiles("*.dcm");

                                    DicomFile file = null;
                                    foreach (FileInfo sopFile in sopInstanceFiles)
                                    {
                                        if (!sopFile.FullName.EndsWith(ServerPlatform.DicomFileExtension))
                                        {
                                            continue;
                                        }

                                        try
                                        {
                                            file = new DicomFile(sopFile.FullName);
                                            file.Load(DicomTags.StudyId, DicomReadOptions.DoNotStorePixelDataInDataSet | DicomReadOptions.Default);
                                            break;
                                        }
                                        catch (Exception e)
                                        {
                                            Platform.Log(LogLevel.Warn, e, "Unexpected failure loading file: {0}.  Continuing to next file.",
                                                         sopFile.FullName);
                                            file = null;
                                        }
                                    }
                                    if (file != null)
                                    {
                                        studyInstanceUid = file.DataSet[DicomTags.StudyInstanceUid].ToString();
                                        break;
                                    }
                                }

                                location = LoadReadableStorageLocation(partition.GetKey(), studyInstanceUid);
                                if (location == null)
                                {
                                    continue;
                                }
                            }

                            ProcessStudy(partition, location, engine, postArchivalEngine, dataAccessEngine);
                            //_stats.NumStudies++;

                            if (CancelPending)
                            {
                                return;
                            }
                        }
                        catch (Exception e)
                        {
                            Platform.Log(LogLevel.Error, e,
                                         "Unexpected error while processing study: {0} on partition {1}.", studyInstanceUid,
                                         partition.Description);
                        }
                    }

                    // Cleanup the directory, if its empty.
                    DirectoryUtility.DeleteIfEmpty(dateDir.FullName);
                }
            }
        }