MedDream DICOM Viewer Install Manual - 2
MedDream DICOM Viewer Install Manual - 2
Table of Contents
1 Introduction 1
1.1 Installation prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2 Requirements 2
2.1 Server-side requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.1.1 Minimal hardware requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.1.2 Software requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.1.3 Time synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.1.4 Licensing (Linux) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2 Client-side requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Decommissioning of MedDream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
5 Deployment 57
5.1 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
5.1.1 Essential configuration and the first run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
5.1.2 System.json . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
5.1.3 Built-in authentication and authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
5.1.4 Predefined login credentials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
5.1.5 The Reporting function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
5.1.6 Adjusting Java memory limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
5.1.7 Enabling SSL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
5.1.8 The external links plugin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.1.9 Reference for remaining configuration parameters . . . . . . . . . . . . . . . . . . . . . . 83
5.1.10 Opening the H2 Console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
5.1.11 Using MySQL for Spring Batch and Quartz Scheduler . . . . . . . . . . . . . . . . . . . . 105
5.1.12 Changing the HTTP context path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
5.1.13 Adjusting a reverse proxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
5.1.14 Caching studies via DICOM Listener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
5.1.15 Monitoring via Prometheus/Grafana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
8 Localization 133
9 Rebranding 133
9.1 Changing the progress bar color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
10 Troubleshooting 137
10.1 Preventive measures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
10.2 Antivirus software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
10.3 Log files of the Java-based core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
10.4 Video conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
10.5 Client side: browser download path selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
10.5.1 Google Chrome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
10.5.2 Mozilla Firefox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
10.5.3 Microsoft Edge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
10.5.4 Safari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
10.6 Client side: enabling clipboard operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
10.7 Client side: monitor calibration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
10.8 Symptom: on Linux the loading pauses just after logging in, possibly with wrong webpage colors . 142
10.9 Symptom: queries to MS SQL Server take seconds from Java but milliseconds from Management
Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
10.10Symptom: video not playable on Firefox under Windows . . . . . . . . . . . . . . . . . . . . . . . . 142
10.11Known limitations and their solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
10.11.1 Share functionality skips some objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
1. Introduction
MedDream Viewer functionality (called “MedDream DICOM Viewer” later in this Manual) is a HTML based
package for PACS server which is designed to aid professionals in every day’s decision-making process,
connecting all the medical data into a unified and fast performing network. MedDream ensures a fast and reliable
way to search, present and analyze the medical data (images and video files) on various devices: computers,
smart phones, tablets and so forth.
MedDream covers: radiology, cardiology, oncology, gastroenterology and many other fields of medical
application. It seamlessly integrates with various medical imaging devices, such as: ultrasound (US),
magnetic resonance (MRI), positron emission tomography (PET), computed tomography (CT), endoscopy (ES),
mammography (MG), digital radiography (DR), computed radiography (CR), ophthalmology and so forth.
Core MedDream DICOM Viewer uses are:
• Replacement of hard copies, e.g., film archives, paper documents, etc.
• Remote access. MedDream provides a possibility to be mobile and work from any place in the world where
the Internet is accessible. More than one person can access and view medical records at one time. Such
functionality speeds up the collaboration among the professionals. So that a doctor in the hospital and a
doctor that is in a different location may view the medical data and discuss about it simultaneously. The
patient’s medical history, various studies and images are found much faster comparing to the conventional
paper-based methods.
• MedDream can be used as a standalone WEB Viewer or integrated into MedDream PACS, PacsOne
PACS, dcm4chee Archive, Conquest, ClearCanvas, Orthanc PACS systems. Moreover, MedDream can be
adapted to client’s PACS system and easily integrated into RIS/HIS workflow.
• MedDream has multiple functions such as search of studies, viewing, analyzing, saving, exporting,
forwarding images and videos, etc.
MedDream is dedicated only to show ePHI (Electronic protected health information) contained in study file.
Administrators, doctors and patients decide how to use ePHI.
Note: Softneta does not keep Electronic Protected Health Information (ePHI).
Make sure the server conforms to the Server-side requirements in the next chapter.
Most installation tasks will require administrative rights on the server (for example, setup of a system service or
adjustment of file system permissions).
Before integrating with a particular system, read the corresponding part of the 3 Integration with PACS chapter
first. That way you’ll know in advance what integration-specific data or cooperation is needed from administrators
of that system. For example, direct integrations will require suitable database credentials, while Query/Retrieve
even requires to configure the PACS accordingly.
Warning: If you are updating to a newer version of MedDream or are applying a “patch” / “hotfix”, please
make a backup of the existing installation. Under Linux this also includes the related system services –
usually not in MedDream directory but elsewhere (depends on distribution).
Warning: When copying large multi-line examples of configuration or shell commands from this document,
pay attention to the typesetting symbols and , like here:
java -XX:MaxRAMPercentage=50.0 -DANTLR_USE_DIRECT_CLASS_LOADING=true -cp␣
˓→MedDream-8.1.0.jar org.springframework.boot.loader.PropertiesLauncher
After copying you need to 1) manually join the lines and remove characters that represent and , 2) add
a space where was present.
Unfortunately, broken lines with line continuation characters \ are not supported by all target environments;
for example, they are OK in Linux shells but not in Windows Command Prompt or PowerShell.
2. Requirements
2.1. Server-side requirements
Note: It is recommended to allocate the fastest disk storage, with free space for 10 days worth of new
studies, for the MedDream cache in order to have a better viewing performance.
The network bandwidth will directly affect image open speed. At least 100 Mbit/s is recommended.
Note: Minimal hardware requirements depend on number of concurrent users, workload and image types. It is
recommended to allocate 20-80% more resources for unusual workload or specific data types.
For security-related configuration, see 7.8 Summary: Minimum relevant IT security requirements.
The MySQL client library does not support server versions below 5.7. This includes any integrations or
authentication mechanisms based on MySQL, and the MySQL variant of reports/attachments storage.
2.1.2.2. Java
MedDream is a Java-based application and requires a JRE. Currently supported Java runtime is Java 17 LTS.
We recommend builds from adoptium.net.
The build must be 64-bit, as under 32-bit builds most kinds of DICOM images will not be displayed.
2.1.2.3. FFmpeg
A 64-bit build of FFmpeg for Windows is included in the installation archive and used automatically on this
platform; a different path can be specified during installation.
In other cases, including Linux, FFmpeg must be installed separately.
The system time needs to be reasonably accurate – for example, within one minute.
MedDream is designed as a single unprivileged application and therefore does not include means of updating
the system time. The time should be synchronized by the operating system instead. It is a responsibility of
the system administrator to set up a network time client and monitor its behavior.
A correct system date is important for adequate behavior of MedDream (the license might contain date-based
limits) and other parts of the infrastructure. Some network time clients even refuse to work when the date is off
by a too large amount.
Under Linux, the most popular form of MedDream license is bound to host name and MAC addresses of network
adapters. The hardware (or virtualization) solution must ensure that they are constant. Using this license in a
Docker container might be impossible unless the MAC is fixed via the --mac-address option of docker run.
Normally dockerized installations, especially cloud-based, imply that an Internet connection is available. For
those we offer a different kind of license that periodically queries our server (lic.softneta.com).
Note: Hardware acceleration should be enabled in web browser for better performance.
Note: MedDream enables users to view all data stored with a bit depth of up to 16 bits per color channel.
However, it displays 8 bits per color channel at a time due to web browser limitations (maximum display of 256
values per color channel). You can utilize the Window leveling tool to explore the entire data range within the
images.
Note: A particular version of MedDream is supported for a limited time (see the Info window or User Manual).
When support is no longer provided, we strongly recommend to update to a supported version. Be aware that
the customer is responsible for outcome (including, but not limited to, personal data protection) from operating a
not supported version. Not supported software versions are used on customer’s own risk.
Bundle-Version: 2.0.10.SNAPSHOT
Warning: Do not mix plugins from different MedDream versions. There is no backwards-compatibility.
Ideally the entire backend will crash immediately (during start) if there is even one incompatible plugin left
in sys/plugins directory. Note that plugins are loaded even if not referenced in application.properties: that
configuration only allows to use them afterwards. In the worst case some unpredictable behavior will happen
later during use.
Warning: In the Direct access to PACS database mode, MedDream must either:
• be installed on the same host as PACS, or
• have access to studies’ files, and likely path remapping needs to be configured.
Some databases contain paths to DICOM files stored on the PACS host (not on some common network storage,
etc.) and it is not always possible to create identical mount points or network drive letters on the MedDream
host.
For this case most PACS plugins support the setting mappedStorageLocation (or with similar name) that
specifies substrings in the path to be replaced with different substrings.
An example with PacsOne plugin: ...].mappedStorageLocation=/volume1/DICOMNL\=O:\|/volume2/
DICOMNL\=P:\. Here /volume1/DICOMNL\ is replaced with O:\ under which the network resource shared by
a Linux system is mounted on a Windows system; in the same fashion /volume2/DICOMNL\ is replaced with P:\.
For best results, please take a look at Java logs for original paths.
Due to limitations of Windows, a service might fail to access a network drive mapped in an interactive session
(even under the same user, even with the “Enable to interact with desktop” turned on). In this case, avoiding a
drive letter should give better results – just remap PACS-local directories to CIFS paths that would otherwise be
attached to a drive letter (...].mappedStorageLocation=/volume1/DICOMNL\=\\server\share\DICOMNL/).
Note: In case of some transient database connection problems, PacsOne saves the received file not under
the configured short-term directory but under /var (Linux) or C:\ (Windows). This results in paths like C:\
2022-04-06-WED\... that will not be accessible from another machine by default. As sharing the entire directory,
even with restrictive file system permissions, is not desired due to security considerations, you should be able
to work around by sharing and remapping particular per-day directories: C:\2022-04-06-WED –> \\server\
anotherShare\2022-04-06-WED etc. This is a recommended temporary solution when doctors need a particular
study up quickly.
A script for easier moving of these files to the intended location is not available yet. To avoid this situation until a
new PacsOne version fixes its behavior, make sure PacsOne is also restarted after restarting MySQL, especially
when it’s on a different host; in particular, always stop the PacsOne service during any MySQL maintenance.
To save Key Objects, Presentation States (measurements), segmentations and secondary capture screenshots,
the following parameters must be added to the configuration of every PACS integration plugin:
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].storeScpIp=127.0.
0.1
IP address (or hostname) of the Storage Server.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].storeScpPort=104
Storage Server Port.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
storeScpAet=PACSONE
Storage Server AE Title.
The local AE Title is configured globally by com.softneta.meddream.dcmsnd.bind as before (default value is
MEDDREAM). The PACS must be configured to accept C-STORE sessions from this AE Title.
Since 7.9, every plugin can have a distinct local AE title:
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
storeScuAet=UPLOADER
If this parameter is commented out or empty, then the global value is used.
All four parameters mentioned above are needed for the Query/Retrieve plugin, too, unless it also has
storageApiEnabled=true; in that case, plugin’s own parameters remoteAET, remoteHost, remotePort and
localAET are used instead.
With most plugins multiple PACSes can be defined simultaneously, then used in the Search window to open
studies (also called “Multi-PACS setup”).
Warning: Opening the same study from different PACSes at the same time is not fully supported. In
particular, the Viewer window doesn’t indicate from which PACS a particular study is opened. This will lead
to confusion, especially in case of different versions of the study (for example, an additional series from a
workstation is present or not).
3.2.1. PacsOne
In case of PacsOne Server (http://pacsone.net/), MedDream implements direct database access mode.
A similar configuration called “Standard DB integration” uses the same plugin and a minimalistic database
structure unrelated to the real PacsOne Server; the database is to be filled by a custom solution implemented
by the customer. Please contact [email protected] for example scripts etc.
Note: “Standard DB integration” doesn’t support saving of annotations and screenshots by itself, the whole
solution is read-only with respect to database and file system. Some customer’s solution is needed to receive
the objects over DICOM C-STORE and update database/files accordingly. The DICOM C-STORE is the only
upload mechanism available at the moment.
Since 8.3.1 MedDream supports downloading of DICOM files that have been stored on AWS S3, including
PacsOne’s long-term storage. Gzip encoding applied by server is transparently removed.
Note: applet.php for MedDream is not included in the installation archive any more. To obtain it, please
contact [email protected].
applet.php is regularly tested with PHP versions from 5.4 to 7.1, though newer ones might also work. It requires
the php_curl PHP module.
Warning: PacsOne and mD Java Core processes must run as the same user because newer versions of
PacsOne create subdirectories with permissions too strict for different users. Please ensure that on Linux
operating systems PacsOne and mD Core services use the same user or belong to the same group.
Warning: PacsOne must store the received DICOM files in the “DicomPart10” format. The other format,
“Native”, is not fully supported by MedDream (and you might have problems with other DICOM-related
software). This setting is chosen during installation and later can be verified as follows:
• Windows: in the registry, REG_SZ StorageFormat under HKEY_LOCAL_MACHINE\SOFTWARE\
RainbowFish Software\PacsOne\${AeTitle};
• Linux: the setting StorageFormat in file(s) *.ini near PacsOne.exe.
PacsOne doesn’t have an index on series.modality. If searches with a particular modality are unacceptably slow
compared to the “All” choice, then you’ll need to use the following MySQL command:
Until 6.0, the HIS integration by Patient ID was using a certain kind of fuzzy matching that includes coerced values
of Patient ID. For example, /?patient=12345 will also list studies with Patient ID “12345[some_original_value]”.
Since 6.0 this is turned off by default. If you still need the legacy behavior, then configure the “PacsOne” plugin
with strictSearchIsEnabled=false. This also changes the Patient History window.
Since MySQL 5.7, the ONLY_FULL_GROUP_BY mode is on by default. Consequently, MedDream’s Search
function uses a compatible and much slower query by default. If performance is paramount, we advise to disable
ONLY_FULL_GROUP_BY and configure the “PacsOne” plugin with useModalityAggregation=false.
The new Reporting function is incompatible with PacsOne’s “studynotes” and “attachment” tables. It is no more
possible to use PacsOne for accessing reports created in MedDream, and vice versa.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
2. If you intend to reuse PacsOne user management, then configure this kind of authentication in
application.properties file:
spring.profiles.include=auth-pacsone
authorization.defaultLoginPermissions=SEARCH,PATIENT_HISTORY,\
UPLOAD_DICOM_LIBRARY
#authorization.users[0].userName=user1
#authorization.users[0].role=DOCUMENT_VIEW,BOUNDING_BOX_EDIT
#authorization.users[0].accessibleStorages=st1,st2
authorization.remapRoles.Doctors=SMART_DRAW_EDIT
authentication.database.databaseName=DB_NAME
authentication.database.jdbcUrl=jdbc:mysql://DB_HOST:DB_PORT/DB_NAME
A different authentication method can still be configured according to 5.1.3 Built-in authentication
and authorization.
3. Edit application.properties file and update the options related to PacsOne plugin. The documentation
below is for plugin version 6.4.0.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].type=PacsOne
Use this specific value of type when connecting to PacsOne.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
id=PacsOneRouter
Identifies the plugin/configuration pair in the search window drop-down menu. You can
connect to multiple PacsOne instances by using different values of id and remaining options.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchApiEnabled=true
(optional) Specifies if this plugin/configuration pair returns a study list for the Search window
and provides study metadata. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imageApiEnabled=true
(optional) Specifies if this plugin/configuration pair retrieves image data. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
forwardApiEnabled=false
(optional) Specifies if PacsOne-specific Forward functionality in the plugin is to be used.
Default is false: MedDream itself reads DICOM files via the plugin (the same way as when
displaying images) and sends them to the recipient, using the same C-STORE client as for
sending new PR/KO objects.
With true, MedDream only creates a forwarding job that is handled by the PacsOne server;
as a result, studies are sent by the PACS service (often on a separate machine). A
single plugin must be configured. A related setting, com.softneta.meddream.dcmsnd.
forwardingMethod=plugin, is required. Database tables “dbjob” and “journal” must be
writeable by the MySQL user identified by username and password below.
In both cases the list of forward destinations is taken from system.json; fetching destinations
from PacsOne database is not supported.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
eventApiEnabled=true
(optional) Specifies if this plugin/configuration pair implements “Clear cache” functionality.
Default is true if dicomCacheDirectory is not empty, and vice versa.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:mysql://127.0.0.1:3306/PACS_DB_NAME
JDBC connection string. Please note that Oracle is not supported (PacsOne Server for
MySQL is the only supported version).
(optional) Default “to” date in YYYYMMDD format when empty in the user interface.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomCacheDirectory=${com.softneta.meddream.tempDir}/dcm/amz1
(optional) A cache directory for files downloaded from AWS S3. Not configured by default,
therefore subsequent access will be slower and will waste AWS traffic.
A cached file is reused forever, there is no support for If-Modified-Since semantics. You’ll
need to set up a separate entry under com.softneta.temp-cleaner.tempItems[] (see
Temporary files cleaner ).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
awsS3Marker=aws_s3
(optional) A magic value that indicates an S3 path instead of a local filesystem path. The
default value is aws_s3, likely hardcoded in PacsOne.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
awsS3Separator=:
(optional) The character that separates awsS3Marker from the remaining path. The default
value is :, likely hardcoded in PacsOne.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
awsS3ConnectionInfoCacheTimeInSec=600
(optional) AWS S3 bucket and region identifiers extracted from the database will be reused
for this many seconds (600 by default).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
encoding=ISO-8859-1
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
encodingTo=ISO-8859-8
(optional) Specify encoding of database strings when it’s not UTF-8.
– encoding=ISO-8859-1, encodingTo=:
(experimental) Use different queries for better performance when the database has been
optimized accordingly (see 3.2.1.4 Optimizing the database (MySQL/MariaDB)).
4. Restart Core for changes to take effect, and navigate to http://127.0.0.1/. Use login credentials
that are valid for chosen method (for example, PacsOne users in case of spring.profiles.
include=auth-pacsone).
After you successfully log into MedDream and are able to access studies on PacsOne, the system can
additionally be configured to open MedDream from PacsOne web interface.
Warning: All users of PacsOne will have the same set of MedDream permissions, configurable in
USER_PRIVILEGES (applet.php) or by authorization.defaultHisPermissions (application.properties). If
some users must not have access to, say, Forward or Reporting, then this restriction is necessary for
everyone.
1. Extract the directory “token-service” from installation archive into a separate directory on the server
(example result: /opt/token-service/token-service.xml). From now on it will be called the installation
directory of the Token Service.
2. Make a backup of PacsOne’s php/applet.php.
3. Copy and Replace MedDream’s applet.php over the PacsOne version of the file.
4. Verify whether MEDDREAM_URL, and especially MEDDREAM_STORAGE_ID, at the beginning are correct.
SSO_VALIDATOR_URL will need correction, too, if the Token Service is configured with a different port
(server.port in its own application.properties).
• If you added MedDream to a legacy PacsOne installation and Apache is proxying it as /meddream,
then MEDDREAM_URL is good already.
• If MedDream is running on a different port without proxying, then MEDDREAM_URL can include the
full address, like //localhost:8080/.
• If you are using MedDreamPACS, which offers MedDream at / and the PACS web interface at /Pacs,
then just use / for MEDDREAM_URL.
5. Start the Token Service from a separate console window: change to its installation directory, then run java
-jar token-service.jar. Wait until the message “Application . . . started” appears.
6. In the PacsOne web interface, find some studies, tick at least one checkbox and click the “Show” button.
security.frameOptionsPolicy=NONE
Note: The “Show” button will appear on patient, study, series and image levels, however MedDream 7.5+
supports the study level only and PacsOne doesn’t allow to hide the button selectively.
For later convenience the token validator should run as a service. The installation directory already provides
helper files token-service.debian, token-service.redhat, token-service.xml, token-service-jar-wrapper.*, token-
service.NET?.exe, a separate version of application.properties. Please follow the 5.2 Running as a service
chapter and do not forget to use the corresponding file names.
Warning: It is recommended to remove or rename PacsOne’s risdirect.php. Our applet.php is not designed
for it, will not work in such a scenario and this combination might cause a slight security risk.
The setting optimized=true depends on certain database optimizations and improves search performance.
• The list of modalities in study is taken from a ready to use column, study.modality_list, instead of
collecting distinct values from related series. This column is not present in PacsOne database schema
(and not in Standard DB Integration schema, too), it must be added manually. We offer a couple of triggers
that update this column automatically.
• If the user enters a search key that starts with “*”, then the search will match anywhere in the text (slower),
instead of only at beginning of the text. Not all involved columns are indexed by default.
Update the schema:
UPDATE study SET modality_list = (SELECT GROUP_CONCAT(DISTINCT modality SEPARATOR ' ') FROM␣
˓→series WHERE series.studyuid = study.uuid);
Add the triggers that will do the same for future studies:
3.2.2. DCM4CHEE
For DCM4CHEE (https://www.dcm4che.org/) MedDream implements the direct database access mode.
Warning: Support for DCM4CHEE 4 was not ported from PHP due to very limited demand.
For DCM4CHEE 2, compatibility is regularly tested only with DCM4CHEE 2.4.17.
In this PACS, when patient name and other demographics are changed in its GUI, the corresponding DICOM
files are not updated on disk (only their copies exported via various interfaces are). But, MedDream does not
merge both sources of data; for example, Info Labels always fetch the attributes from the file, and will therefore
show outdated information. The setting com.softneta.meddream.newObjectsUseMetadataFromPacs can
only compensate for a single aspect of the issue, however there are more. If patient demographics
are often corrected at the PACS instead of the modality, we recommend to use Q/R or DICOMweb
integration instead. MedDream 8.1 alleviates that to some extent by adding Q/R support to the DCM4CHEE
plugin: if patient demographics were updated on the PACS, then corresponding DICOM files will be
downloaded via a C-MOVE request.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
2. Choose and configure a universal authentication method according to 5.1.3 Built-in authentication and
authorization.
3. Edit application.properties file and update the options related to DCM4CHEE 5.x plugin. The
documentation below is for plugin version 6.2.0.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
type=Dcm4chee5
Use this specific value of type when connecting to DCM4CHEE 5.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
id=MainArchive
Identifies the plugin/configuration pair in the search window drop-down menu. You can
connect to multiple DCM4CHEE instances by using different values of id and remaining
options.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchApiEnabled=true
(optional) Specifies if this plugin/configuration pair returns a study list for the Search window
and provides study metadata. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imageApiEnabled=true
(optional) Specifies if this plugin/configuration pair retrieves image data. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:mysql://127.0.0.1:3306/PACS_DB_NAME
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:postgresql://127.0.0.1:5432/PACS_DB_NAME
JDBC connection string. Supported DBMSes are MySQL and PostgreSQL.
In case of connection problems it might be necessary to add some more parameters to this
string: useJDBCCompliantTimezoneShift=true for a time zone shift, serverTimezone=UTC
for a specific timezone, useSSL=false to disable SSL, etc. (The first parameter-value
pair is preceded by “?”, the remaining pairs – by “&”.) See https://dev.mysql.com/doc/
connector-j/5.1/en/connector-j-reference-configuration-properties.html for MySQL, or https:
//jdbc.postgresql.org/documentation/head/connect.html for PostgreSQL.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
username=UserName
Username used to connect to the database.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
password=UserPassword
Password used to connect to the database.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
encoding=ISO-8859-1
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
encodingTo=ISO-8859-8
(optional) Specify encoding of database strings when it’s not UTF-8.
– encoding=ISO-8859-1, encodingTo=:
(experimental) Since 8.0.0 plugins are expected to return the full DICOM-formatted patient
name, like “last^first^middle^prefix^suffix=ideographic=phonetic”, for proper reformatting in
Core (also see personNameConfiguration in system.json.) false turns this off and is
normally not required.
4. Restart Core for changes to take effect, and navigate to http://127.0.0.1/. Use login credentials that
are valid for chosen method.
The plugin can detect whether patient demographics are changed: it parses AttributeModificationDateTime in
the “dicomattrs.attrs” database record referenced by the “patient” table, and compares with a value cached on
disk. If a newer value is found, then the cached one is updated and a C-MOVE request downloads updated
DICOM files to the local C-STORE SCP. Therefore MedDream can read up-to-date files from its own cache. If
patient demographics were not changed, then MedDream reads the original DICOM files by their paths in the
database.
This mechanism is a compromise between direct integration (the fastest) and Q/R (provides up-to-date DICOM
files). The slower mode will be used only for studies with updated patient demographics.
Note: Make sure that MedDream, PACS and DBMS are on the same time zone, or else the changes might not
be detected correctly.
The timestamps are compared only when the following options are configured:
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].localAET=MEDDREAM
The AE Title of the C-MOVE client, and the destination of C-MOVE operations.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
remoteAET=DCM4CHEE
The AE Title of the remote machine.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].remoteHost=127.0.
0.1
IP address or hostname of the remote machine.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].remotePort=11112
Port number of the remote machine.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
patientUpdateCacheDir=${com.softneta.meddream.tempDir}/timestamps
Directory for caching timestamps of patient demographics records. As a combination of plugin’s
.id and Study UID is hashed and distributed among subdirectories, you can use the same
patientUpdateCacheDir for multiple instances of the plugin.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].cacheDir= ${com.
softneta.dicomStoreService.saveDirectory}/DCM4CHEE/
A directory for DICOM files from remoteAET received by the local C-STORE SCP.
The remaining options are for slight adjustments of the behavior:
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].retryDelay=1000
Period in milliseconds for checking whether the DICOM file has been received.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].timeout=10000
Maximum total duration in milliseconds for waiting for a received file.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
fetchStudyAfterStructure=false
Start the C-MOVE command (if needed according to timestamps) as early as possible: just after
fetching the study structure, not on actual request to fetch a DICOM file.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
useSessionCache=false
When true, every session has its own subdirectory under cacheDir that is cleaned automatically
when the session ends (cleaning also requires options eventApiEnabled=true and com.
softneta.preparation.useSessionCache=true).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
useSessionPatientUpdateCache=false
When true, every session has its own subdirectory under patientUpdateCacheDir
that is cleaned automatically when the session ends (cleaning also requires options
eventApiEnabled=true and com.softneta.preparation.useSessionCache=true).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
eventApiEnabled=false
Set this to true together with useSessionCache or useSessionPatientUpdateCache (and also
com.softneta.preparation.useSessionCache) for automated cleaning of per-session caches.
Since 8.3.0, true is the default value when Q/R mode is configured (options localAET,
remoteAET, remoteHost, remotePort, cacheDir, patientUpdateCacheDir are present).
Furthermore, EventAPI also implements the “Clear caches” functionality at the plugin side.
When set to false, the plugin will support neither “Clear caches” nor automated cleaning of per-
session caches. If explicitly set to true, however Q/R mode is not configured, the plugin won’t
attempt any cleaning, too.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
2. (Option 1) Choose and configure a universal authentication method according to 5.1.3 Built-in
authentication and authorization.
3. (Option 2) If you intend to (partially) reuse DCM4CHEE user management, then configure this kind of
authentication in application.properties file:
spring.profiles.include=auth-dcm4chee
authentication.database.username=APP_USER
authentication.database.password=APP_PASS
authentication.database.jdbcUrl=jdbc:mysql://DB_HOST:DB_PORT/DB_NAME
authorization.defaultLoginPermissions=EXPORT_ARCH,EXPORT_ISO,FORWARD,\
DOCUMENT_VIEW
authorization.remapRoles.Doctor=SEARCH
authorization.remapRoles.WebAdmin=ADMIN
authorization.users[0].userName=user
authorization.users[0].role=UPLOAD_DICOM_LIBRARY,REPORT_UPLOAD
4. Edit application.properties file and update the options related to DCM4CHEE 2.x plugin. The
documentation below is for plugin version 5.1.0.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
type=Dcm4chee2
Use this specific value of type when connecting to DCM4CHEE 2.x.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].id=RouterPacs
Identifies the plugin/configuration pair in the search window drop-down menu. You can
connect to multiple DCM4CHEE instances by using different values of id and remaining
options.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchApiEnabled=true
(optional) Specifies if this plugin/configuration pair returns a study list for the Search window
and provides study metadata. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imageApiEnabled=true
(optional) Specifies if this plugin/configuration pair retrieves image data. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:mysql://127.0.0.1:3306/PACS_DB_NAME
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:postgresql://127.0.0.1:5432/PACS_DB_NAME
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:sqlserver://127.0.0.1:1433;database=PACS_DB_NAME
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:oracle:thin://127.0.0.1:1521/xe
JDBC connection string. Supported DBMSes are MySQL, PostgreSQL, Microsoft SQL
Server and Oracle.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
username=UserName
Username used to connect to the database.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
password=UserPassword
Password used to connect to the database.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
defaultStoragePath=C:/DCM4CHEE_INSTALL_DIR/server/default
Base directory for relative paths. By default DCM4CHEE stores the files relative to a certain
location below the installation directory (see the example), unless one sets up in advance an
absolute filesystem prefix via addRWFileSystem() in JMX Console.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
charset=latin1
(optional) Defines the character set used in the database. If not empty, conversion from this
character set to UTF-8 is attempted; otherwise the data is passed as is (default). utf8 might
work in case of double encoding.
Note: The PACS GUI (/dcm4chee-web, /dcm4chee-web3, etc) is able to correctly display
data even if the database server was configured incorrectly before sending the images and
therefore parts of the database accessed by the plugin now contain garbled text or question
marks (information is permanently lost already). DCM4CHEE has a certain workaround
against this situation; there is no equivalent of it in the plugin.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
enableStatistics=false
(optional) true enables query statistics such as query time and so on. You might also want
to set logging.level.org.hibernate=DEBUG in application.properties to get more details.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
mappedStorageLocations=D:/DICOM=Y:\\DICOM1|E:/DICOM=Y:\\DICOM2
(optional) Defines replacement paths for MedDream that is installed on a different host than
the PACS, and is accessing images through mapped network drives or network paths.
We recommend to configure defaultStoragePath with a ready to use value, instead of using a
PACS-local value and adding a separate replacement rule here. Of course the corresponding
folder must be shared on the PACS, too.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
addPatientBirthDateToDescription=false
(optional) If true, Study Description is prefixed by Patient’s Birth Date. This is for display only
– searching by this date is not possible.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomPersonName=false
(experimental) Since 8.0.0 plugins are expected to return the full DICOM-formatted patient
name, like “last^first^middle^prefix^suffix=ideographic=phonetic”, for proper reformatting in
Core (also see personNameConfiguration in system.json.) false turns this off and is
normally not required.
5. Restart Core for changes to take effect, and navigate to http://127.0.0.1/. Use login credentials that
are valid for chosen method.
The plugin can detect whether patient demographics are changed: it compares the database field
“patient.updated_time” with “patient.created_time” and a value cached on disk. If a newer value is found, then
the cached one is updated and a C-MOVE request downloads updated DICOM files to the local C-STORE SCP.
Therefore MedDream can read up-to-date files from its own cache. If patient demographics were not changed,
then MedDream reads the original DICOM files by their paths in the database.
Note: Make sure that MedDream, PACS and DBMS are on the same time zone, or else the changes might not
be detected correctly.
This mechanism is a compromise between direct integration (the fastest) and Q/R (provides up-to-date DICOM
files). The slower mode will be used only for studies with updated patient demographics.
The timestamps are compared only when the following options are configured:
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].localAET=MEDDREAM
The AE Title of the C-MOVE client, and the destination of C-MOVE operations.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
remoteAET=DCM4CHEE
The AE Title of the remote machine.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].remoteHost=127.0.
0.1
IP address or hostname of the remote machine.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].remotePort=11112
Port number of the remote machine.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
patientUpdateCacheDir=${com.softneta.meddream.tempDir}/timestamps
Directory for caching timestamps of patient demographics records. As a combination of plugin’s
.id and Study UID is hashed and distributed among subdirectories, you can use the same
patientUpdateCacheDir for multiple instances of the plugin.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].cacheDir=${com.
softneta.dicomStoreService.saveDirectory}/DCM4CHEE/
A directory for DICOM files from remoteAET received by the local C-STORE SCP.
The remaining options are for slight adjustments of the behavior:
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].retryDelay=1000
Period in milliseconds for checking whether the DICOM file has been received.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].timeout=10000
Maximum total duration in milliseconds for waiting for a received file.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
fetchStudyAfterStructure=false
Start the C-MOVE command (if needed according to timestamps) as early as possible: just after
fetching the study structure, not on actual request to fetch a DICOM file.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
useSessionCache=false
When true, every session has its own subdirectory under cacheDir that is cleaned automatically
when the session ends (cleaning also requires options eventApiEnabled=true and com.
softneta.preparation.useSessionCache=true).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
useSessionPatientUpdateCache=false
When true, every session has its own subdirectory under patientUpdateCacheDir
that is cleaned automatically when the session ends (cleaning also requires options
eventApiEnabled=true and com.softneta.preparation.useSessionCache=true).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
eventApiEnabled=false
Set this to true together with useSessionCache or useSessionPatientUpdateCache (and also
com.softneta.preparation.useSessionCache) for automated cleaning of per-session caches.
Since 8.3.0, true is the default value when Q/R mode is configured (options localAET,
remoteAET, remoteHost, remotePort, cacheDir, patientUpdateCacheDir are present).
Furthermore, EventAPI also implements the “Clear caches” functionality at the plugin side.
When set to false, the plugin will support neither “Clear caches” nor automated cleaning of per-
session caches. If explicitly set to true, however Q/R mode is not configured, the plugin won’t
attempt any cleaning, too.
3.2.3. ClearCanvas
For ClearCanvas (https://clearcanvas.ca/) MedDream implements the direct database access mode.
Warning: Because the commercial version of ClearCanvas became end-of-life in 2020, support is tested
only ocassionally. MedDream 8.0.0 was not tested.
As IIS occupies the port 80, MedDream will need to run on a different port (the server.port setting). If
MedDream URL looks “not nice” because of that, then you can use IIS as a reverse proxy; please contact
[email protected] for instructions.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
2. Choose and configure a universal authentication method according to 5.1.3 Built-in authentication and
authorization.
3. Edit application.properties file and update the options related to ClearCanvas plugin. The
documentation below is for plugin version 5.1.0.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
type=ClearCanvas
Use this specific value of type when connecting to ClearCanvas.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].id=OldArchive
Identifies the plugin/configuration pair in the search window drop-down menu. You can
connect to multiple ClearCanvas instances by using different values of id and remaining
options.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchApiEnabled=true
(optional) Specifies if this plugin/configuration pair returns a study list for the Search window
and provides study metadata. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imageApiEnabled=true
(optional) Specifies if this plugin/configuration pair retrieves image data. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:sqlserver://127.0.0.1:1433;database=ImageServer
URL should be specified in format: jdbc:sqlserver://<HOST>\\<INSTANCE>:<PORT>;
database=<DATABASE_NAME>
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
username=UserName
Username used to connect to the database.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
password=UserPassword
Password used to connect to the database.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
mappedStorageLocation=C:\\FS=Z:\\Studies
(optional) Defines pair of path strings that should be replaced in order to use mapped
storages. Syntax for defining strings: “oldPathPart=newPathPart”.
In case of multiple rules, separate them by pipe character and enter more specific ones first:
E:\\DICOM2=\\\\CLRCANVAS-SRV\\DICOM2\|E:\\DICOM=Z:\\DICOM.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
strictSearchIsEnabled=
(optional) true forces exact matching by Patient ID and Accession Number everywhere,
including the Search window. false forces wildcard matching everywhere, including HIS
integration by Patient ID or Accession Number, and the Patient History window. null or unset
is the default: exact matching for Patient History and HIS integration, wildcard matching for
Search window.
4. Restart Core for changes to take effect, and navigate to http://127.0.0.1:MEDDREAM_PORT/. Use login
credentials that are valid for chosen method.
3.2.4. Conquest
MedDream does not support the proprietary “V2 (allows NKI compression)” image format. All images that were
received by Conquest with this setting on, including those of the example patient “HEAD EXP2”, will be unusable.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
2. Choose and configure a universal authentication method according to 5.1.3 Built-in authentication and
authorization.
3. Edit application.properties file and update the options related to Conquest plugin. The documentation
below is for plugin version 5.1.1.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
type=Conquest
Use this specific value of type when connecting to Conquest.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
id=ResearchPacs
Identifies the plugin/configuration pair in the search window drop-down menu. You
can connect to multiple Conquest instances by using different values of id and
remaining options.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchApiEnabled=true
(optional) Specifies if this plugin/configuration pair returns a study list for the Search
window and provides study metadata. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imageApiEnabled=true
(optional) Specifies if this plugin/configuration pair retrieves image data. Default is
true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:mysql://127.0.0.1:3306/PACS_DB_NAME
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:postgresql://127.0.0.1:5432/PACS_DB_NAME
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
url=jdbc:sqlserver://127.0.0.1:1433;database=PACS_DB_NAME
JDBC connection string. Supported DBMSes are MySQL, PostgreSQL, Microsoft
SQL Server, dBASE 3.
MS SQL server isn’t directly supported by Conquest. This is a special case
when Conquest uses an ODBC source backed by the SQL Server, and
MedDream connects to the server directly.
Please contact [email protected] if you would like to use dBASE 3
integration.
In case of connection problems it might be necessary to add some more parameters
to this string, like useSSL=false to disable SSL. (The first parameter-value
pair is preceded by “?”, the remaining pairs – by “&”.) See https://dev.mysql.
com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.html
for MySQL, or https://jdbc.postgresql.org/documentation/head/connect.html
for PostgreSQL, or https://docs.microsoft.com/en-us/sql/connect/jdbc/
setting-the-connection-properties?viewFallbackFrom=sql-server-previousversions
for Microsoft SQL Server.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
username=UserName
Username used to connect to the database.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
password=UserPassword
Password used to connect to the database.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
pathToDicomIni=E:\\Conquest\\dicom.ini
Full path to the Conquest configuration file dicom.ini. MedDream will read
MAGDeviceXXX=... lines from it.
There is no “mappedStorageLocation” configuration option like in other plugins. In
case when MedDream is on a different host, one can copy dicom.ini to a file on
MedDream host, leave only MAGDeviceX lines and update them with shared paths
that are accessible on MedDream host. For example, MAGDevice1=E:\DICOM might
change to MAGDevice1=\\conquest-srv\dicomstorage1.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
useModalityAggregation=true
(optional) Aggregate results in the DBMS (not in the plugin). Performance might
become worse.
false by default, and can’t be set to true for MS SQL Server or dBASE 3.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
encoding=ISO-8859-1
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
encodingTo=ISO-8859-8
(optional) Specify encoding of database strings when it’s not UTF-8.
– encoding=ISO-8859-1, encodingTo=:
3.3.1. Orthanc
For Orthanc (https://www.orthanc-server.com/) MedDream uses its custom Web API. DICOM files are also
downloaded through it, and can be cached for better performance.
Direct database access wasn’t implemented as it would likely offer little performance gain due to database
schema complexity. You might try the DICOM mode as an alternative.
The API is not used to authenticate users because tested versions of Orthanc offer only global credentials (for a
single user). These credentials must still be entered in plugin configuration, though.
When using preparation triggered by forwarding of images to the DICOM Listener, you should use the
onStableStudy event in Orthanc for forwarding. Immediate forwarding (before the import to Orthanc database
has finished), like based on the onStoreInstance event, will result in problems as MedDream won’t be able to
get recent study metadata this early. The example Lua script can be obtained from [email protected].
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
2. Choose and configure a universal authentication method according to 5.1.3 Built-in authentication and
authorization.
3. Edit application.properties file and update the options related to Orthanc plugin. The documentation
below is for plugin version 5.0.1.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].type=Orthanc
Use this specific value of type when connecting to Orthanc.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
id=Telemedicine
Identifies the plugin/configuration pair in the search window drop-down menu. You can
connect to multiple Orthanc instances by using different values of id and remaining options.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchApiEnabled=true
(optional) Specifies if this plugin/configuration pair returns a study list for the Search window
and provides study metadata. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imageApiEnabled=true
(optional) Specifies if this plugin/configuration pair retrieves image data. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
eventApiEnabled=false
(optional) Set this to false in order to disable support for “Clear caches”. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
baseUrl=http://127.0.0.1:8042
Base URL that points to the root of Orthanc Web API. (Endpoints /tools/find, /instances
etc will be appended automatically.)
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
username=UserLogin
Username for Basic Authentication.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
password=UserPassword
Password for Basic Authentication.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomCacheDirectory=${com.softneta.meddream.tempDir}/dcm/Telemedicine
(optional) A directory for caching images and study structure. Without this setting a
file is downloaded anew every time and it’s not possible to examine the contents for
troubleshooting. Study structure is cached together with a “last study update” timestamp from
Orthanc; this ensures that an updated structure is always fetched from the server (excess
caching is prevented).
This plugin supports URIs (starting with file://). Making them relative to tempDir or another
setting is encouraged to minimize human errors.
Multiple instances of this plugin should have different directories in order to not mix up
potentially different versions of the file with the same Study/Series/SOP Instance UIDs.
As of MedDream 7.5.1+, this directory is not cleaned automatically and you need to configure
a separate entry under com.softneta.temp-cleaner.tempItems[] (see Temporary files
cleaner ).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
cacheDicomFiles=true
(optional) If false, dicomCacheDirectory is used only for caching the study structure.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
pythonPlugin=false
(optional) true enables a faster method of fetching the study structure. However the Python
plugin and a custom script from Softneta must be configured in Orthanc; see the next chapter.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
strictSearchIsEnabled=true
(optional) true forces exact matching by Patient ID and Accession Number everywhere,
including the Search window. false forces wildcard matching everywhere, including HIS
integration by Patient ID or Accession Number, and the Patient History window. null or unset
is the default: exact matching for Patient History and HIS integration, wildcard matching for
Search window.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchPoolSize=10
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imagePoolSize=10
(optional) Maximum number of threads for fetching search results or metadata, and
downloading DICOM files, respectively. Increasing the value might improve performance,
however it also increases probability of timeouts and then raising searchRequestRepeat /
imageRequestRepeat is advised.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchRequestRepeat=15
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imageRequestRepeat=5
(optional) In case of download failure the request will automatically be retried this number of
times. Each retry is delayed by 300 ms, 600 ms, 900 ms and so on.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
nonStrictSearchPattern=00100020:*{value}*;00080050:*{value}*
(optional) Specifies where to put wildcard characters when implementing a non-strict search.
The value in the example is used by default, and yields the same behavior as before.
Entries are separated with ;. Format of the entry is <tag code>:<value pattern>. The
<value pattern> part must contain a placeholder {value} that will be replaced with the
search key; furthermore, space characters in the key are replaced with *. Currently
recognized values for <tag code> are 00100020 and 00080050.
This would match only values beginning with the search key: 00100020:{value}*;
00080050:{value}*.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchSymbols=*,?
(optional) Comma-separated list of wildcard characters. They aren’t allowed in strict search
scenarios, and will yield an error message.
The default value with two characters from the Standard is a security improvement: it makes
sure that the PACS won’t return studies to which the end user has no acccess. An empty
string means pre-8.0 behavior.
In non-strict scenarios, including strictSearchIsEnabled=false or keys like Study Description,
these characters are used to decide that the search key is good enough — namely, it
doesn’t need formatting by nonStrictSearchPattern and spaces aren’t to be replaced with
asterisks. When the end user is using the Search window, (s)he can explicitly add wildcards
where deemed appropriate: for example, PID001 is sent to the PACS as *PID001*, PID 001
– *PID*001*, PID001* – PID001*, PID?001 – PID?001.
4. Restart Core for changes to take effect, and navigate to http://127.0.0.1/. Use login credentials that
are valid for chosen method.
The Python plugin in Orthanc allows scripting custom behavior. A script from Softneta (available below) returns
study metadata significantly faster than the dedicated method of Orthanc API.
import json
import orthanc
def GetStudyInfo(output, uri, **request):
studyId = request['groups'][0]
info = []
instances = orthanc.RestApiGet('/studies/%s/instances?expand' % studyId)
series = orthanc.RestApiGet('/studies/%s/series' % studyId)
for serie in json.loads(series):
tags = serie['MainDicomTags']
tags['OrthancSeriesID'] = serie['ID']
tags['ParentStudy'] = serie['ParentStudy']
info1 = []
info1.append(tags1)
tags['Instances'] = info1
info.append(tags)
(continues on next page)
output.AnswerBuffer(json.dumps(info), 'application/json')
orthanc.RegisterRestCallback('/studies/(.*)/info', GetStudyInfo)
Orthanc in Docker
The easiest and fastest way to have Orthanc with Python plugin is to use a Docker image that already includes
the plugin: https://hub.docker.com/r/jodogne/orthanc-python.
For example, if you are installing MedDream with Orthanc and want to use the Python plugin, then use the
following commands:
Orthanc in Docker
Verify that Python plugin is activated by opening your plugins page, for example: http://localhost:8042/app/
explorer.html#plugins.
Copy softneta.py to any suitable location in Docker container, for example:
In the configuration file orthanc.json, verify path to the plugins directory and add the path to your script, for
example:
"Plugins" : [
"/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"
],
"PythonScript" : "/usr/local/share/orthanc/plugins/softneta.py",
It might be easier to copy orthanc.json from the container to your environment (docker cp orthanc:/etc/
orthanc/orthanc.json orthanc.json), edit and then copy it back (docker cp orthanc.json orthanc:/etc/
orthanc/orthanc.json).
Afterwards the container must be restarted (docker restart orthanc).
Orthanc under Windows
Verify that Python plugin is activated by opening your plugins page, for example: http://localhost:8042/app/
explorer.html#plugins.
Copy softneta.py to any suitable location, for example, C:\Orthanc\softneta.py.
In the configuration file orthanc.json, verify path to the plugins directory and add the path to your script, for
example:
"Plugins" : [ "../Plugins/" ],
"PythonScript" : "C:\\Orthanc\\softneta.py",
"Plugins" : [
"/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"
],
"PythonScript" : "/usr/local/share/orthanc/plugins/softneta.py",
1. Open any study in Orthanc and copy the value of “uuid” parameter from the browser address
bar. For example, http://localhost:8042/app/explorer.html#study?uuid=dddddddd-cccccccc-bbbbbbb-
00000000-aaaaaaaa.
2. Open a new tab and try to access the following URL (update the UUID with value from step 1): http:
//localhost:8042/studies/dddddddd-cccccccc-bbbbbbb-00000000-aaaaaaaa/info.
For example, if the study address was http://localhost:8042/app/explorer.html#study?uuid=c4dfb8ab-
762b8b76-9a068673-4dbba15b-24167200, then the test URL shall be http://localhost:8042/studies/
c4dfb8ab-762b8b76-9a068673-4dbba15b-24167200/info.
You should be able to see some JSON-formatted information.
3.3.2. DICOMweb
Universal HTTP-based communication over RESTful protocols like QIDO-RS and WADO-RS, and the legacy
WADO-URI protocol.
WADO-RS does not provide means to request a particular set of attributes. Study metadata from a server
inclined to return all attributes can be enormous. It is advised to minimize the amount of data:
• Some non-standard parameter, like “dataset=meddream”, could be implemented in the server to support
optimal and reduced attribute sets at the same time.
• The server could be configured for a reduced set if MedDream is the sole client.
• Some PACSes might return a smaller set of attributes via SearchForInstances of QIDO-RS, compared
to RetrieveMetadata of WADO-RS. In that case, specify a full URL in studyMetaUrl (with as many
“includefield” parameters as needed) and leave the wadoRsUrl option empty.
The DICOM Standard does not offer an attribute for the date/time when the study was received by the PACS.
Similarly there is some confusion regarding which attribute should indicate Application Entity Title of the sender.
As a result, typical PACSes do not return this data and MedDream search columns “Received On” and “Source
AE” remain empty. If you’ll find out what tags a particular PACS uses, then they can be configured via plugin
options studyReceivedDateTag and sourceAeTitleTag.
The plugin supports the following authentication choices:
• no authentication;
• HTTP Basic Authentication;
• a custom HTTP POST (or, alternatively, GET) to a configurable address that accepts HTML FORM
variables “login” and “password”, and returns HTTP 200/202 with a configurable cookie. This cookie is
included in all subsequent requests and automatically refreshed when needed;
• Google Cloud service authentication for using a Google Cloud Healthcare data store instead of a PACS. It
is enough to specify a JSON file downloaded from Cloud Console that contains keys and other parameters;
• Microsoft Azure authentication (based on client ID, client secret and OAuth2 URL that includes the tenant
ID).
When configuring a custom query in URLs, do not attempt to override some parameters added by the plugin
dynamically; as the plugin does not check for duplicates, the server will likely accept the second occurrence (the
duplicate from the plugin) instead.
Google Healthcare requires a reasonably accurate machine clock. A very large difference (tens of minutes) with
respect to Google servers will result in an “Invalid JWT” error. Azure might have a similar effect because the
token lifetime is just one hour.
3.3.2.2. Compatibility
Search operation uses SearchForStudies of QIDO-RS protocol, the header “Accept: application/dicom+json” is
used by default (can be overridden). Attributes recognized in the response are:
• (0008,0020) Study Date
• (0008,0030) Study Time
• (0008,0050) Accession Number
• (0008,0061) Modalities In Study
• (0008,1030) Study Description
• (0010,0010) Patient Name
• (0010,0020) Patient ID
• (0020,000D) Study Instance UID
• configurable custom attribute for AE Title(s) of senders contributing to the study
• configurable custom attribute for study reception date/time
Most of them can also be used as query keys.
A certain filter, if enabled, checks the value of (0020,1208) Number Of Study Related Instances and silently
aborts if the attribute is not present.
Fetching study metadata uses RetrieveMetadata of WADO-RS protocol, the header “Accept:
application/dicom+json” is used by default (can be overridden). Alternatively, it is possible to configure a
full URL that results in an equivalent list of instances and their attributes, like SearchForInstances of QIDO-RS.
Attributes recognized in every SOP instance are:
• (0002,0010) Transfer Syntax UID
• (0008,0020) Study Date
• (0008,0016) SOP Class UID
• (0008,0018) SOP Instance UID
• (0008,0030) Study Time
• (0008,0050) Accession Number
• (0008,0060) Modality
• (0008,0090) Referring Physician’s Name
• (0008,1030) Study Description
• (0008,103E) Series Description
• (0010,0010) Patient Name
• (0010,0020) Patient ID
• (0010,0030) Patient Birth Date
• (0020,000E) Series Instance UID
• (0020,0010) Study ID
• (0020,0011) Series Number
• (0020,0013) Instance Number
• (0028,0008) Number Of Frames
• configurable custom attribute for AE Title(s) of senders contributing to the study
Download of a DICOM file can use WADO-URI protocol or RetrieveInstance of WADO-RS protocol. WADO-RS
can return the file directly or wrapped in a “multipart/related” MIME container, however only the first body in
the container, regardless of headers, is considered. The default Accept header is “application/dicom; transfer-
syntax=*” (Google Cloud mode) or just “application/dicom” (others); the value can be overridden regardless of
integration.
Uploading annotations and screenshots can use StoreInstances of STOW-RS protocol (disabled by default in
favor of the global C-STORE based mechanism). The default header is “Accept: application/dicom+json” (can
be overridden).
DICOM XML format for metadata and other responses is not supported.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
2. Choose and configure a universal authentication method according to 5.1.3 Built-in authentication and
authorization.
3. Edit application.properties file and update the options related to DICOMweb plugin. The
documentation below is for plugin version 6.2.0; examples are from integrations with DCM4CHEE 5.25,
Orthanc 1.5.8 with OrthancDicomWeb 1.0, PacsOne 7.2 and Google Cloud Healthcare as of June 2022.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].type=Dicomweb
Use this specific value of type when connecting via DICOMweb.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
id=MainArchiveDW
Identifies the plugin/configuration pair in the search window drop-down menu. You can
connect to multiple PACSes by using different values of id and remaining options.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchApiEnabled=true
(optional) Specifies if this plugin/configuration pair returns a study list for the Search window
and provides study metadata. Default is true.
When targeting an older PacsOne installation that supports WADO-URI only, you can
use false here and choose a different plugin (PacsOne or even QR) with same id and
imageApiEnabled=false as the counterpart.
Speaking of any PACS, this plugin’s Image API can be used as an alternative if sharing
DICOM files over the network is somehow not possible and slower operation is not an issue.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imageApiEnabled=true
(optional) Specifies if this plugin/configuration pair retrieves image data. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
eventApiEnabled=false
(optional) true, together with useSessionCache=true and com.softneta.preparation.
useSessionCache=true, enables cleaning of per-session cache subdirectories when the
sessions end, and support for “Clear caches” at the plugin side.
Default is true since 8.3.0.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
storageApiEnabled=true
(optional) Specifies if this plugin/configuration pair is used to store annotations and
screenshots (instead of the universal C-STORE based mechanism). Default is false.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
qidoRsUrl=http://127.0.0.1:8080/dcm4chee-arc/aets/DCM4CHEE/rs?fuzzymatching=true
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
qidoRsUrl=http://127.0.0.1:8042/dicom-web
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
qidoRsUrl=https://healthcare.googleapis.com/v1/projects/P1/locations/L2/datasets/
D3/dicomStores/S4/dicomWeb?fuzzymatching=true
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
qidoRsUrl=https://my-azure-test-123.dicom.azurehealthcareapis.com/v1?
fuzzymatching=true
Base URL of QIDO-RS API. Can include a query for additional or non-standard parameters.
(The endpoint /studies and relevant dynamic parameters will be appended automatically.)
In this example, DCM4CHEE 5, Google Cloud and Azure require the “fuzzymatching”
parameter or else searching by Patient Name is not possible at all.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
wadoRsUrl=http://127.0.0.1:8080/dcm4chee-arc/aets/DCM4CHEE/rs
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
wadoRsUrl=http://127.0.0.1:8042/dicom-web
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
wadoRsUrl=https://healthcare.googleapis.com/v1/projects/P1/locations/L2/datasets/
D3/dicomStores/S4/dicomWeb
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
wadoRsUrl=https://my-azure-test-123.dicom.azurehealthcareapis.com/v1
Base URL of WADO-RS API. Can include a query for additional or non-standard parameters.
(The endpoint /studies will be appended automatically.)
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
studyMetaUrl=http://127.0.0.1:8080/dcm4chee-arc/aets/DCM4CHEE/rs/studies/{study}/
metadata
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
studyMetaUrl=http://127.0.0.1:8042/dicom-web/studies/{study}/instances?
includefield=00100010&includefield=00100020&includefield=00100030&
includefield=00080020&includefield=00080030&includefield=00080090&
includefield=00280008
Alternative to wadoRsUrl. This is a full URL, not its base part; you must specify the query
part, too, if needed. The placeholder {study} can appear anywhere.
The second example in fact means QIDO-RS instead of WADO-RS. This makes no difference
for the plugin, as long as the response format is the same.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
metaAcceptHeader=application/json
(optional) Overrides the default Accept header application/dicom+json for search and
study structure.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
metaCustomHeader=x-test-1: value1
(optional) Adds custom header(s) for search and study structure. Multiple entries are also
possible, by using | as separator: x-test-1: value1|x-test-2: value2|....
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
wadoUriUrl=http://127.0.0.1:8080/dcm4chee-arc/aets/DCM4CHEE/wado
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
wadoUriUrl=http://127.0.0.1:8042/wado
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
wadoUriUrl=http://127.0.0.1/wado.php
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
wadoUriUrl=http://127.0.0.1/wado.php?username=UserLogin&password=UserPassword
Base URL of WADO-URI API. Can include a query for additional or non-standard parameters.
(The relevant dynamic parameters will be appended automatically.)
Google Cloud Healthcare and Azure DICOM service do not support WADO-URI, use
dicomFileUrl instead.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomFileUrl=http://127.0.0.1:8042/wado?requestType=WADO&studyUID={study}
&seriesUID={series}&objectUID={image}&contentType=application%2Fdicom
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomFileUrl=http://127.0.0.1:8080/dcm4chee-arc/aets/DCM4CHEE/rs/studies/{study}/
series/{series}/instances/{image}
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomFileUrl=https://healthcare.googleapis.com/v1/projects/P1/locations/L2/datasets/
D3/dicomStores/S4/dicomWeb/studies/{study}/series/{series}/instances/{image}
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomFileUrl=https://my-azure-test-123.dicom.azurehealthcareapis.com/v1/studies/
{study}/series/{series}/instances/{image}
Alternative to wadoUriUrl. This is a full URL, not its base part; you must specify the query
part, too, if needed. Placeholders {study}, {series} and {image} can appear anywhere.
The examples 2. . . 4 in fact mean WADO-RS instead of WADO-URI. This makes no difference
for the plugin, as long as the PACS still returns the DICOM file directly – or in the
“multipart/related” format that is also indicated by the Content-Type header. (DCM4CHEE
5 supports only multipart from RetrieveInstance, see fileAcceptHeader.)
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
fileAcceptHeader=application/dicom
(optional) Overrides the default Accept header for file downloads (application/
dicom; transfer-syntax=* if googleCloudConfigFile is configured, or application/dicom
otherwise).
To request a multipart format from PACSes that don’t support other formats, try multipart/
related; type="application/dicom".
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
fileCustomHeader=x-test-1: value1
(optional) Adds custom header(s) for file downloads. Multiple entries are also possible, by
using | as separator: x-test-1: value1|x-test-2: value2|....
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
stowRsUrl=http://127.0.0.1:8042/dicom-web
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
stowRsUrl=http://127.0.0.1:8080/dcm4chee-arc/aets/DCM4CHEE/rs
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
stowRsUrl=https://healthcare.googleapis.com/v1/projects/P1/locations/L2/datasets/
D3/dicomStores/S4/dicomWeb
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
stowRsUrl=http://127.0.0.1/stowrs.php
Base URL of STOW-RS API. Can include a query for additional or non-standard parameters.
(The relevant dynamic parameters will be appended automatically.)
Azure DICOM service doesn’t support the optional Study Instance UID that is automatically
appended to this URL; use uploadUrl instead.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
uploadUrl=http://127.0.0.1:8042/dicom-web/studies/{study}
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
uploadUrl=http://127.0.0.1:8080/dcm4chee-arc/aets/DCM4CHEE/rs/studies/{study}
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
uploadUrl=https://healthcare.googleapis.com/v1/projects/P1/locations/L2/datasets/
D3/dicomStores/S4/dicomWeb/studies/{study}
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
uploadUrl=http://127.0.0.1/stowrs.php/studies/{study}
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
uploadUrl=https://my-azure-test-123.dicom.azurehealthcareapis.com/v1/studies
Alternative to stowRsUrl. This is a full URL, not its base part. The {study} placeholder can
appear anywhere. By the way, this parameter provides an opportunity to omit the standard
“/studies/{study}” part because the latter is always automatically appended to stowRsUrl.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
sendAcceptHeader=application/json
(optional) Overrides the default Accept header (application/dicom+json) for uploading
annotations and screenshots.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
sendCustomHeader=x-test-1: value1
(optional) Adds custom header(s) for uploading annotations and screenshots. Multiple
entries are also possible, by using | as separator: x-test-1: value1|x-test-2:
value2|....
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
username=UserLogin
(optional) Username for Basic Authentication, custom form authentication or Azure
authentication (in the latter case this parameter expects the client ID, like 123e4567-e89b-
12d3-a456-426652340000).
Not needed for default configuration of DCM4CHEE 5. Definitely needed for Orthanc with
AuthenticationEnabled=true. Needed for PacsOne by default unless credentials are included
in the URL (less secure).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
password=UserPassword
(optional) Password for Basic Authentication, custom form authentication or Azure
authentication (in the latter case this parameter expects the client secret, like
SW4gdGhlIGJlZ2lubmluZyB3YXMgdGhlIFdvcmQ=).
Not needed for default configuration of DCM4CHEE 5. Definitely needed for Orthanc with
AuthenticationEnabled=true. Needed for PacsOne by default unless credentials are included
in the URL (less secure).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
loginUrl=http://server/path
(optional) URL for a custom form authentication with username parameter login and
password parameter password. If empty and azureAuthUrl is also empty, then Basic
Authentication or no authentication (depending on whether both username and password
are configured) is used instead.
Obviously not applicable to DCM4CHEE, Orthanc or PacsOne.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
loginWithGET=true
(optional) When true, loginUrl is used to perform a GET request instead of POST.
Credentials (login and password) are automatically added to the URL.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
loginCookie=MySessionCookie
(optional) Cookie name for a custom form authentication. Default value is “suid”.
Obviously not applicable to DCM4CHEE, Orthanc or PacsOne.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
azureAuthUrl=https://login.microsoftonline.com/936da01f-9abd-4d9d-80c7-02af85c822a8/
oauth2/token
(optional) Enables the Azure authentication (loginUrl must be empty). The URL must be
in form shown above; the GUID is to be replaced with your tenant ID on Azure platform.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
googleCloudConfigFile=C:\MedDreamPACS-Premium\MedDream\gc-login.json
(optional) Turns on Google Cloud Healthcare integration mode: a certain authentication and
a different default Accept header for file downloads. Do not forget to use dicomFileUrl instead
of wadoUriUrl.
The file must contain a service account private key in JSON format, as created by the IAM &
Admin console.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
<name>.tag=1048624
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
<name>.type=string
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
<name>.level=STUDY
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
<name>.strict=false
(optional) Remapping of attributes sent to the PACS as query/return keys and collected from
the response. Also see 5.1.17 Custom columns in Patient History / Patient Studies for the
overall idea.
Fully tested values of <name> for this plugin are sourceAe, receivedDate, custom1 . . .
custom10. More will be documented in the future.
.tag specifies the tag of a DICOM attribute – an integer in decimal notation, e. g.,
(0123,4567) => 0x01234567 => 19088743. The columns “sourceAe” (was configured
via sourceAeTitleTag before MedDream 8.2) and “receivedDate” (was configured via
studyReceivedDateTag) are ignored by default as their .tag is zero.
.type specifies additional processing of the value. object (default) means none. number is
converted to Integer or Double. For string, missing value is replaced with “”. For date, a date
formatted as yyyMMdd is converted to yyyy-MM-dd. For time, a time formatted as HHmmss
is converted to HH:mm:ss. personName, when dicomPersonName=false, replaces every “^”
with a space. You can safely use string with the columns “sourceAe” and “receivedDate”
mentioned above.
.level specifies where to request the attribute and expect it in the response. Default is STUDY,
can be changed to SERIES or IMAGE.
.strict (false by default) can disable adding of wildcards by default when this attribute is used
as a search key. The overall scenario and strictSearchIsEnabled can still override it. See
also nonStrictSearchPattern, searchSymbols.
Migration for “sourceAe” and “receivedDate” from pre-8.2 versions looks as follows:
#com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
˓→sourceAeTitleTag=1048624
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
˓→sourceAe.tag=1048624
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
(continues on next page)
#com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
˓→studyReceivedDateTag=19106219
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
˓→receivedDate.tag=19106219
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
˓→receivedDate.type=string
In 8.2+ it’s still possible to specify any study-level attribute for .columns.sourceAe.tag or
.columns.receivedDate.tag that the PACS is able to return. sourceAe should also work as
a search key; receivedDate is only a return key. But, the column in search results will
still have the original name which might confuse insufficiently trained end users. The only
workaround (when using a single plugin) is to rename the text in the translation file; for
English it’s ...,"sourceAE":"Source AE",... or ...,"receivedOn":"Received On",...
in sys/locales/en/translation.*.json.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
multipleModalitySupport=true
(optional) false will yield an error message when the user selects multiple modalities. Use
this if the PACS does not support multiple modalities and search results confuse the users
(nothing is found).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
multivalueSeparatorIsComma=false
(optional) Since 4.3.0, the Modality filter is comma-separated by default, as recent versions
of the Standard require this more clearly and more PACSes are following it. Earlier the
Standard was referring to Query/Retrieve semantics; some PACSes (or their older versions)
might still expect a backslash-separated filter in QIDO-RS queries, and you’ll need to use
false in those cases.
A couple of tested PACSes return no results when this setting is incorrect and more than one
modality is selected in the Search window. But, this still won’t help if multiple modalities aren’t
supported at all (see multipleModalitySupport).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomCacheDirectory=${com.softneta.meddream.tempDir}/dcm/MainArchiveDW
(optional) A directory for caching images. Without this setting a file is downloaded anew
every time and examining its contents for troubleshooting becomes difficult.
This plugin supports URIs (starting with file://). Making them relative to tempDir or another
setting is encouraged to minimize human errors.
Multiple instances of this plugin should have different directories in order to not mix up
potentially different versions of the file with the same Study/Series/SOP Instance UIDs.
As of MedDream 7.5.1+, this directory is not cleaned automatically and you need to configure
a separate entry under com.softneta.temp-cleaner.tempItems[] (see Temporary files
cleaner ). useSessionCache below mitigates the situation to some extent.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
useSessionCache=true
(optional) Enables per-session cache subdirectories. Default is false.
The main benefit is that together with eventApiEnabled=true and com.softneta.
preparation.useSessionCache=true, a session subdirectory is cleaned automatically when
the session ends (for example, the user logs off). As a result, the DICOM files are cached for
the shortest time possible. The temporary files cleaner is then needed mainly for unforeseen
situations like application crashes or server restarts.
On the other hand, when one user opens a particular study, then afterwards other users won’t
experience faster loading of the same study as the entire study is downloaded again for each
of them.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
strictSearchIsEnabled=false
(optional) true forces exact matching by Patient ID and Accession Number everywhere,
including the Search window. false forces wildcard matching everywhere, including HIS
integration by Patient ID or Accession Number, and the Patient History window. null or unset
is the default: exact matching for Patient History and HIS integration, wildcard matching for
Search window.
true is required for Google Cloud Healthcare due to its limitations. Furthermore, Google
Cloud does not support searching by Study Description and MedDream is unable to handle
this gracefully.
true is required for Azure DICOM service, too. As of August 2022, the service supports
fuzzy matching only for the Patient Name attribute and all other attributes must match exactly
(wildcards are considered a literal part of the query).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
badUtf8Filter=true
(optional) true enables a workaround for incorrectly encoded UTF-8 characters in JSON
responses related to qidoRsUrl, wadoRsUrl and studyMetaUrl.
The issue should be fixed in the PACS instead, as the workaround costs some performance
overhead. Enable it only if search operations, or attempts to open a certain study, are failing
and the application log contains a JsonMappingException complaining about “Invalid UTF-8”.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
sCSeriesLowerPriority=true
(optional) true shifts series with Secondary Capture objects (classes . . . 1.1.7, . . . 1.1.7.*)
further in the thumbnail strip by adding 10000 to the Series Number attribute of those objects.
This is disabled by default.
Since 8.3.1 the alternative is the Core setting com.softneta.study.
lowerPrioritySeriesModalities: it works for all plugins, selects series by value of
Modality and moves them more effectively (there is no hardcoded increment of Series
Number that might be insufficient for some studies).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
allowDuplicateObject=NO
(optional) Graceful handling of duplicate objects in the same series.
MedDream uses the SOP Instance UID as a unique key when downloading a DICOM
file, therefore the study structure (and response from wadoRsUrl/studyMetaUrl) can’t have
multiple entries with the same SOP Instance UID. But, it is possible to selectively ignore
some of them.
If the PACS always returns a more recent copy earlier, then you can safely choose KEEP:
MedDream will use the first entry and ignore further duplicates.
If the PACS always returns a more recent copy later, then you can safely choose REPLACE:
MedDream will update the object attributes from every duplicate, effectively using the last
entry.
The risk behind a wrong choice is that MedDream will prepare itself for the value of an
attribute found in the study structure, but later the PACS will return a DICOM file with a
different value of the same attribute. Results might be unpredictable as MedDream is not
tested with this kind of misinformation.
The default value is NO and duplicates will cause an error like before version 4.9.0.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
logResponseAmount=256
(optional) Change how many bytes of the server response are logged at DEBUG level.
The default value of zero corresponds to 512 for file downloads and 524288 for
search/metadata. A configured value replaces both limits at once.
A common usage is to reduce size of the application logs due to a smaller value, like 32. A
value larger than 512K can help when troubleshooting a crash related to parsing of JSON
data.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomPersonName=true
(experimental) Return Patient Name and Referring Physician Name with DICOM separators
(^) and include all five components. If false, return only last name and first name separated
by a space. The ideographic and phonetic component groups are never returned, though.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
multivalueSeparatorIsComma=true
(optional) When false, multiple values of a search key (e. g., Modalities In Study) are
delimited with backslashes and not commas. This might be needed by older PACSes.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
nonStrictSearchPattern=00100020:*{value}*;00080050:*{value}*
(optional) Specifies where to put wildcard characters when implementing a non-strict search.
The value in the example is used by default, and yields the same behavior as before.
Entries are separated with ;. Format of the entry is <tag code>:<value pattern>. The
<value pattern> part must contain a placeholder {value} that will be replaced with the
search key; furthermore, space characters in the key are replaced with *. Currently
recognized values for <tag code> are 00100020 and 00080050.
This would match only values beginning with the search key: 00100020:{value}*;
00080050:{value}*.
This forces exact matching for Patient ID and Accession Number even with
strictSearchIsEnabled=false: 00100020:{value};00080050:{value}.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchSymbols=*,?
(optional) Comma-separated list of wildcard characters. They aren’t allowed in strict search
scenarios (except otherStrictSearchTags), and will yield an error message.
The default value with two characters from the Standard is a security improvement: it makes
sure that the PACS won’t return studies to which the end user has no acccess. An empty
string means pre-8.0 behavior.
In non-strict scenarios, including strictSearchIsEnabled=false or keys like Study Description,
these characters are used to decide that the search key is good enough — namely, it
doesn’t need formatting by nonStrictSearchPattern and spaces aren’t to be replaced with
asterisks. When the end user is using the Search window, (s)he can explicitly add wildcards
where deemed appropriate: for example, PID001 is sent to the PACS as *PID001*, PID 001
– *PID*001*, PID001* – PID001*, PID?001 – PID?001.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
otherStrictSearchTags=524384,19088743
(optional) Override which non-integration attributes are used as strict search filters. Tag
numbers must be in decimal notation and separated by commas.
Supported values are Modality (specified by 524384, which is the same as 0x00080060) and
Source AE Title (specified by the same nonzero value as in sourceAeTitleTag).
Modality is included by default, therefore you can use an empty string for a non-strict search
by modality. Keep in mind afterwards that some standard modality codes include each other,
like “US” will also match “IVUS”, “OP” will also match “OPV”, etc. This will be useful for
PACSes that are unable to find, say, “MR” in a list like “KO,MR,PR”.
Both attributes are partially subject to searchSymbols. A query key is allowed to contain this
kind of wildcard character; if there is one, and otherStrictSearchTags does not configure
a strict search for the key, then leading and trailing * characters are added unconditionally –
without using nonStrictSearchPattern.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchPageSize=500
(optional) Maximum value of the QIDO-RS “limit” parameter (hard limit on search results)
when MedDream’s legacy value, 1000, is too large for the server.
If less than 1000, then MedDream performs multiple requests with corresponding “offset” and
“limit” parameters until up to 1000 results are collected in total.
By default it’s 200 when azureAuthUrl is not empty, and 1000 otherwise.
A value not in range 1. . . 1000 yields a warning and is replaced with a default. The Azure
DICOM server, in turn, supports a shorter range – 100. . . 200.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchSkipsSingleObjOfMods=KO,PR
(optional) Search results will not contain records where Modalities In Study has a single
value matching any entry in this comma-separated list and Number Of Study Related
Instances is 1.
This option was created as a workaround for a certain PACS that lists studies consisting of a
single certain SR object, yet is unable to return study metadata for it and the error message
confuses the end users.
It could also be used to hide studies consisting of a single non-image object like MedDream’s
own KO, PR or RTSTRUCT: studies like these will result in a message about an empty study.
4. Restart Core for changes to take effect, and navigate to http://127.0.0.1/. Use login credentials that
are valid for chosen method.
The parameters qidoRsUrl, wadoRsUrl, studyMetaUrl, wadoUriUrl, dicomFileUrl, stowRsUrl, uploadUrl and
googleCloudConfigFile can have 4 placeholders “custom1” . . . “custom4” for integration-specific dynamic
values:
• {custom1}
• {custom1:DEFAULT_VALUE}
• {custom1:}
• ...
• {custom4:DEFAULT_VALUE}
(in the 3rd example, the default value is an empty string).
Only those four are supported. Other documented placeholders – “{study}”, “{series}” and “{image}” – are
handled elsewhere. Any other (unknown) placeholder name will result in a fatal error.
Dynamic values come from the “storageConfiguration” part of the HIS integration token. The corresponding
parameters there are called DICOMWEB_CUSTOM_1 . . . DICOMWEB_CUSTOM_4.
If the default value isn’t specified together with the placeholder, then a corresponding dynamic value must be
provided in the token. This means that when MedDream is used both interactively and from HIS, the default
values are unavoidable.
For example, the setting ...[0].googleCloudConfigFile=/opt/meddream/gc-{custom1:interactive}.json
refers to a file “gc-interactive.json” for scenarios with MedDream login and search, while a token
{
"items": [ ],
"storageConfiguration": [ { "storage": "gc1", "parameters": [
{ "name": "DICOMWEB_CUSTOM_1", "value": "his" }
] } ]
}
Note: The bundled token service doesn’t recognize DICOMWEB_CUSTOM_* by default and needs the
following configuration string in its own application.properties file:
validate.storage-configurations.parameter-list=DICOMWEB_CUSTOM_1,DICOMWEB_CUSTOM_2,\
DICOMWEB_CUSTOM_3,DICOMWEB_CUSTOM_4
3.3.3. Amazon S3
The following JSON file illustrates the supported metadata. Attributes are grouped into study level and
instance+series levels (MedDream afterwards uses series-level attributes in the latter for proper grouping into
series).
The plugin ignores the Content-Type response header and always parses the payload as JSON.
{
"instanceUid": "1.2.3",
"studyDate": "20140710",
"studyTime": "084944.000",
"studyReceivedDate": "",
"studyId": "1",
"studyDescription": "PLC CT CHE-ABD-PEL-CORONARY CAL SCORE-VIRTUAL COLONOSCOPY",
"accessionNumber": "1000801048",
"referringPhysicianName": "DOE^JOSEPH^X.",
"modalitiesInStudy": "CT",
"sourceAETitle": "",
"patientId": "200091016",
"patientName": "DOE^JOHN",
"patientBirthDate": "19710107",
"sops": [
{
"seriesInstanceUid": "4.5.6.70",
"seriesDescription": "Cardiac 3.0 Cardiac/Score",
"modality": "CT",
"seriesNumber": "2",
"sopClassUid": "1.2.840.10008.5.1.4.1.1.2",
"transferSyntaxUid": "1.2.840.10008.1.2",
"instanceNumber": "4",
"sop": "8.9.10.100",
"frameCount": 1,
"dicomUrl": "https://some-server.s3.us-east-2.amazonaws.com/dicom/1.2.3/4.5.6.70/8.9.
˓→10.100.dcm?X-Amz-Credential=...&X-Amz-Signature=..."
},
{
"seriesInstanceUid": "4.5.6.71",
"seriesDescription": "Body 5.0",
"modality": "CT",
"seriesNumber": "3",
"sopClassUid": "1.2.840.10008.5.1.4.1.1.2",
"transferSyntaxUid": "1.2.840.10008.1.2",
"instanceNumber": "2",
"sop": "8.9.10.100",
"frameCount": 1,
"dicomUrl": "https://some-server.s3.us-east-2.amazonaws.com/dicom/1.2.3/4.5.6.71/8.9.
˓→10.101.dcm?X-Amz-Credential=...&X-Amz-Signature=..."
}
]
}
The Search window is not supported. If enabled, its contents will remain empty. This is a typical HIS integration.
There is no specific authentication/authorization between MedDream and S3, or between MedDream and
the manifest service. In general, DICOM files in the S3 bucket must be either readable anonymously (the
s3:ListBucket permission should be denied, though), or accessible due to X-Amz-Credential and similar
options in the URL. The implementer can choose any convention that results in short-lived URLs. The manifest
service should be accessible only by MedDream – due to a firewall, to an IP address whitelist, or just by listening
on a loopback address in the same machine.
Currently it is not possible to configure a REST-like URL, or the entire URL including the query part, for
downloading the manifest. The query part ?studyInstanceUID=<UID> is blindly added to the configured endpoint
address. This prevents hosting of a static manifest on the same S3 bucket.
Other manifest formats, like Basic Directory IOD (DICOMDIR), are not supported at the moment.
The downloaded DICOM files are always cached on disk, and the corresponding configuration option (cache
directory) is mandatory.
Do not configure the two settings common to most plugins, searchApiEnabled and imageApiEnabled. The
values are true by default, and false will not work properly: particularly, ImageAPI of this plugin depends on
URLs cached by its SearchAPI.
Saving annotations will not work unless the customer’s solution includes a DICOM Storage SCP that propagates
the changes both to the S3 and the manifest service.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
1. Configure the HIS integration (preferably token-based) in application.properties file:
spring.profiles.include=auth-his
#authentication.his.validHisParams=study
authentication.his.token-service-address=http://127.0.0.1:8088/v2/validate
authorization.defaultHisPermissions=EXPORT_ISO,EXPORT_ARCH,FORWARD,\
UPLOAD_DICOM_LIBRARY,DOCUMENT_VIEW,BOUNDING_BOX_VIEW
com.softneta.cache.studyStructureSec=0
Now the manifest service will be always queried when reloading a study. This is important
if URLs to DICOM objects expire after a short time.
2. Edit application.properties file and update the options related to Amazon S3 plugin. The
documentation below is for plugin version 3.0.1.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].type=AmazonS3
Use this specific value of type.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].id=S3
Identifies the plugin/configuration pair. You can use multiple manifest services etc. by using
different values of id and remaining options.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
eventApiEnabled=false
(optional) false will turn off “Clear caches” support in the plugin. True by default.
Note that this is not related to automatic cleaning of the cache when the session ends. This
plugin, unlike some others, doesn’t support the useSessionCache setting and its cache is
always global.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
studyStructureServiceUrl=http://internal-production-alp.us-east-2.elb.amazonaws.
com/Integration/GetStructureByStudy
The endpoint that returns a manifest JSON given the Study Instance UID. A query ?
studyInstanceUID=... is added automatically.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomCacheDirectory=${com.softneta.meddream.tempDir}/dcm/AmazonS3
Cache directory for received files.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
dicomUrlMappingItemsCount=300000
(optional) Size of the URL cache. The default value is 250000.
MedDream is able to communicate over DICOM 3.0 native interface (Upper Layer Protocol, ULP) with any PACS
that supports Query/Retrieve and Storage.
The Query/Retrieve SCU identifies itself as “MEDDREAM” by default. (Do not forget to configure the PACS to
accept connections from this AET.) This can be changed by the localAET setting of the plugin. Binding to a
particular port is usually not required, and Java-based MedDream still doesn’t support that.
The plugin also contains its own Store SCU that is used to send annotations and screenshots back to the PACS.
(With other plugins, a common DICOM SCU in Java Core is used, see 3.1.2 Saving measurements, Key Objects,
segmentations and screenshots.) If you choose this, then:
• the plugin-level settings storeScpIp, storeScpPort and storeScpAet (for the common DICOM SCU) are
not needed – the plugin uses the same remoteHost, remotePort and remoteAET as for Query/Retrieve;
• its Calling AE Title is configured by the localAET plugin setting, instead of storeScuAet or com.softneta.
meddream.dcmsnd.bind;
• uploading via the plugin also requires its setting storageApiEnabled=true.
The local Store SCP (receives files during a C-MOVE session) is implemented not in the plugin but in Java
Core, and can function in parallel to any other plugin if needed. It must bind to a port (we recommend 11116)
and by default listens on 127.0.0.1 (com.softneta.dicomStoreService.address can specify a single address
or 0.0.0.0, a wildcard for any available IP address). The mandatory settings are:
• com.softneta.dicomStoreService.localAETitle – accepted Called AE Title (also multiple comma-
separated values, or even empty),
• com.softneta.dicomStoreService.port,
• com.softneta.dicomStoreService.acceptAETitles – known Calling AE Titles,
• com.softneta.dicomStoreService.saveDirectory – base directory for received files.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
2. Choose and configure some universal authentication method according to 5.1.3 Built-in authentication and
authorization.
3. Edit application.properties file and update the options related to Query/Retrieve plugin. The
documentation below is for plugin version 6.0.0.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].type=QR
Use this specific value of type when connecting to a PACS over the DICOM 3.0 protocol.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
id=AnonStudies
Identifies the plugin/configuration pair in the search window drop-down menu.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchApiEnabled=true
(optional) Specifies if this plugin/configuration pair returns a study list for the Search window
and provides study metadata. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
imageApiEnabled=true
(optional) Specifies if this plugin/configuration pair retrieves image data. Default is true.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
eventApiEnabled=false
(optional) true by default. If set to true (or commented out) together with
useSessionCache=true and com.softneta.preparation.useSessionCache=true, the per-
session cache is cleared automatically when session ends.
If set to true (or commented out), support for “Clear caches” at the plugin side is enabled. In
case of “useSessionCache” settings mentioned above, will clean the user-specified part of
both per-session and global caches.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
storageApiEnabled=true
(optional) Specifies if this plugin/configuration pair is used to send
PR/KO/segmentation/screenshot objects back to its PACS (instead of using the mechanism
common to all plugins). Default is false.
You can try this option when there are some problems with PR/KO sending, as the Store
SCU in the plugin is a bit different. The parameters storeScpAet, storeScpIp, storeScpPort
and storeScuAet are then not used.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
remoteAET=PACSONE
The AE Title of the remote machine.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
remoteHost=127.0.0.1
IP address or hostname of the remote machine.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
remotePort=104
Port number of the remote machine.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
localAET=MEDDREAM
The AE Title of the DICOM C-FIND/C-MOVE/C-STORE clients implemented in this plugin.
Also used as the C-MOVE destination.
Multiple values (separated by comma) can be entered if the local Store SCP is configured
with multiple Called AE Titles. This might improve performance due to parallel sessions.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
cFindLocalAET=MDR
(optional) If not empty, overrides localAET for C-FIND sessions (C-MOVE sessions always
remain unchanged).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
cacheDir=${com.softneta.dicomStoreService.saveDirectory}/PACSONE/
A directory with images that are received by local C-STORE SCP in the background. The
trailing slash/backslash is mandatory.
The last subdirectory must be equal to remoteAET, as the local SCP adds one automatically
to the configured base directory.
This plugin supports URIs (starting with file://). Making them relative to receiver’s
saveDirectory is encouraged to minimize human errors.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].timeout=90000
(optional) DICOM file receive timeout in milliseconds (starting from the C-MOVE request).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
retryDelay=1000
(optional) DICOM file existence check period in milliseconds.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
strictSearchIsEnabled=true
(optional) true forces exact matching by Patient ID and Accession Number everywhere,
including the Search window. false forces wildcard matching everywhere, including HIS
integration by Patient ID or Accession Number, and the Patient History window. null or unset
is the default: exact matching for Patient History and HIS integration, wildcard matching for
Search window.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
multipleModalitySupport=true
(optional) false will yield an error message when the user selects multiple modalities. Use
this if the PACS does not support multiple modalities and search results confuse the users.
If explicitly configured with true, the plugin performs a workaround for a certain PACS: a
filter by modality “ECG” will also match a non-standard modality “ECGEP”. Keep the option
commented out if this is undesired.
When this option is commented out (default), both the error message and the modality
workaround are turned off.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
defaultStartDate=20181107
(optional) Default “from” date in YYYYMMDD format when empty in the user interface. This is
for some PACSes that require the Study Date search key in every C-FIND request.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
defaultEndDate=20181108
(optional) Default “to” date in YYYYMMDD format when empty in the user interface. This is for
some PACSes that require the Study Date search key in every C-FIND request.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
studyLevelRequest=false
(optional) Value for query attribute (0008,0052) Query/Retrieve Level: STUDY if true (default),
SERIES if false.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchCharset=ISO_IR 144
(optional) Convert search keys from UTF-8 to this encoding. Default is empty (no
conversion).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
structureResultCharset=ISO_IR 144
(optional) If the PACS didn’t specify result encoding, then convert search results from this
encoding to UTF-8. Default is empty (no conversion).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
useSessionCache=true
(optional) Enables session-scope caching. When true, every session gets its own
cache subdirectory (the plugin moves, or copies, globally received files to session-related
subdirectories). It is forcefully cleaned when the session ends (cleaning also requires
eventApiEnabled and com.softneta.preparation.useSessionCache).
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].cmove.
requestSeriesFirstInstances=0
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].cmove.
filterModalitiesIfStudyHasMoreInstance=500
(optional) The cmove.filterModalities logic is enabled only when number of instances in the
study exceeds this amount.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].cmove.
requestAfterStructureLevel=SERIES
(optional) If “SERIES”, fetches each of the missing or incomplete series separately (performs
a series-level C-MOVE). “STUDY” will fetch the entire study at once.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
nonStrictSearchPattern=00100020:*{value}*;00080050:*{value}*
(optional) Specifies where to put wildcard characters when implementing a non-strict search.
The value in the example is used by default, and yields the same behavior as before.
Entries are separated with ;. Format of the entry is <tag code>:<value pattern>. The
<value pattern> part must contain a placeholder {value} that will be replaced with the
search key; furthermore, space characters in the key are replaced with *. Currently
recognized values for <tag code> are 00100020 and 00080050.
This would match only values beginning with the search key: 00100020:{value}*;
00080050:{value}*.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
searchSymbols=*,?
(optional) Comma-separated list of wildcard characters. They aren’t allowed in strict search
scenarios, and will yield an error message.
The default value with two characters from the Standard is a security improvement: it makes
sure that the PACS won’t return studies to which the end user has no acccess. An empty
string means pre-8.0 behavior.
In non-strict scenarios, including strictSearchIsEnabled=false or keys like Study Description,
these characters are used to decide that the search key is good enough — namely, it
doesn’t need formatting by nonStrictSearchPattern and spaces aren’t to be replaced with
asterisks. When the end user is using the Search window, (s)he can explicitly add wildcards
where deemed appropriate: for example, PID001 is sent to the PACS as *PID001*, PID 001
– *PID*001*, PID001* – PID001*, PID?001 – PID?001.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
allowDuplicateObjects=NO
(optional) Handling of objects with the same SOP Instance UID found in same series.
Objects like these signal a serious flaw in the PACS, especially if they have different attributes:
you are no more sure which version of the object will be sent to MedDream later when
requested by the same SOP Instance UID (attributes in the structure might be misleading).
NO (default) disallows the duplicates and the study doesn’t open.
KEEP ignores any duplicates, therefore attributes of the first occurrence are preserved. If the
PACS wants to return all versions of the object and they are properly sorted in descending
order by reception time, then this is the safe value.
REPLACE updates the attributes of the earlier entry. If the PACS wants to return all versions
of the object and they are properly sorted in ascending order by reception time, then this
is the safe value.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
<name>.tag=1048624
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
<name>.type=string
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
<name>.level=STUDY
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.
<name>.strict=false
(optional) Remapping of attributes sent to the PACS as query/return keys and collected from
the response. Also see 5.1.17 Custom columns in Patient History / Patient Studies for the
overall idea.
Fully tested values of <name> for this plugin are sourceAe, receivedDate, report, custom1
. . . custom10. More will be documented in the future.
.tag specifies the tag of a DICOM attribute – an integer in decimal notation. The columns
“sourceAe” (was configured via sourceAeTitleTag before MedDream 8.2) and “receivedDate”
(was configured via studyReceivedDateTag) are ignored by default as their .tag is zero. The
column report is a new functionality for read-only reports implemented by the customer and
also ignored by default.
.type specifies additional processing of the value. object (default) means none. number is
converted to Integer or Double. For string, missing value is replaced with “”. For date, a date
formatted as yyyMMdd is converted to yyyy-MM-dd. For time, a time formatted as HHmmss
is converted to HH:mm:ss. personName, when dicomPersonName=false, replaces every “^”
with a space. You can safely use string with the columns “sourceAe”, “receivedDate” and
“report” mentioned above.
.level specifies where to request the attribute and expect it in the response. Default is STUDY,
can be changed to SERIES or IMAGE.
.strict (false by default) can disable adding of wildcards by default when this attribute is used
as a search key. The overall scenario and strictSearchIsEnabled can still override it. See
also nonStrictSearchPattern, searchSymbols.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
reportURL=http://127.0.0.1:8088/report/{studyUid}
(optional) A URL (or file system path) template for accessing customer-implemented reports
(see 5.1.5.4 Remote reports for details). A placeholder {studyUid} is replaced with Study
Instance UID, and {storageId} – with .id of this plugin configuration.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
maxConnections=5
(optional) Limit on C-MOVE sessions from a particular plugin instance (a single “storage”),
shared between all concurrent user connections. 1000 by default.
Does not affect C-FIND sessions so far; their number will depend on concurrent users as
before.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
blacklistedSopClasses=1.2.840.113619.4.30
(optional) Comma-separated list of SOP Class UID values (empty by default) to be filtered
out from the study structure. Similar to “blackListedSopClasses” in system.json but at a lower
level: even PR, KO, etc can be completely hidden from MedDream this way.
Objects with a matching attribute might also avoid a C-MOVE to MedDream. However, if not
all images from a series were blacklisted but the plugin decides to do a series-level C-MOVE,
or not all series were blacklisted but the plugin decides to do a study-level C-MOVE, then the
PACS will still attempt to send the object among the “good” ones.
The main purpose of this setting is to avoid C-MOVE sessions of objects (or series, or even
studies) consisting entirely of listed objects. For example, a sub-association related only
to private SOP Classes unsupported by the local C-STORE SCP usually fails with an error
that is reported back to MedDream and interferes with loading of the study. In contrast, if
that association also contains supported objects, transfer of the latter succeeds with just a
warning which MedDream ignores.
4. Restart Core for changes to take effect, and navigate to http://127.0.0.1/. Use login credentials that
are valid for configured method.
This MedDream mode allows to view single DICOM files, or directories containing DICOM files (of a single study
or multiple studies). In fact, no PACS is necessary.
However there is no search functionality. A HIS (or equivalent application) must track studies/images
together with corresponding paths and offer hyperlinks to MedDream.
MedDream is opened with a relative path to a single file, or to a directory. Absolute paths are not allowed due to
security concerns.
If a directory is specified, then DICOM files are collected directly below it by default. Number of scanned
subdirectories can be increased by the maxDepth plugin option.
Warning: As of 7.7.0+, there is only a limited support for copies of the same DICOM file (same
Study/Series/SOP Instance UIDs) in different directories. These directories must be accessed via separate
sessions with different /?file=. . . values (or their token-based equivalents); a single session must use different
multiple entries in the “file” parameter. Accessing at once via a common value, like a parent directory, is not
possible. The most obvious situation is where all files are kept together without subdirectories, and at least
one file is duplicate; duplicates will then be ignored, warnings will only be seen in the log, it might be counter-
intuitive which file is parsed first and therefore treated as a reference for finding duplicates.
The Reporting function is not recommended at all: it will treat such copies as different studies, their reports
might become mixed up after restarting the backend and reopening the studies again. Saving of key objects
and measurements might be problematic, too.
The specified directory must contain DICOM files only. Filtering by name pattern or extension is not
supported. Typical “DICOMDIR” files (the Basic Directory IOD, SOP Class “1.2.840.10008.1.3.10”) will be
ignored if encountered during a directory scan, and are specifically disallowed as a target of the “file” parameter
(using them as an alternative to directory scanning is not implemented).
This plugin supports a custom HIS integration parameter “file”. Due to architectural shortcuts, it also supports
the ubiquitous parameter “study”. But, the latter is not intended for HIS integration; if used this way, it will work
only for a short time (until a particular in-memory cache expires) after successfully opening the corresponding
studies via “file”.
Do not set searchApiEnabled or imageApiEnabled in plugin configuration to false, as this plugin can’t be
combined with others, even with other plugin instances of the same type.
The login form is not needed to view images and can therefore remain disabled together with the Search window.
However both features are needed to access the Settings dialog if the USER_SETTINGS permission is not
suitable. For that one must log in interactively as a user with the “ADMIN” permission.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
1. Configure the HIS integration in application.properties file:
spring.profiles.include=auth-his
authentication.his.validHisParams=file
authentication.his.maxObjects=10
authorization.defaultHisPermissions=EXPORT_ISO,EXPORT_ARCH,FORWARD,\
UPLOAD_DICOM_LIBRARY,DOCUMENT_VIEW,BOUNDING_BOX_VIEW
The “maxObjects” setting allows to limit the number of studies that is allowed to open at once. If the
directory specified in /?file=. . . contains more, the operation will fail. This prevents situations where
too many objects would render the frontend unusable.
2. Plan how MedDream settings will be changed:
• (Option 1) Choose and additionally configure some universal authentication method according
to 5.1.3 Built-in authentication and authorization, then add both “ADMIN” and “SEARCH”
permissions to some users. These users will be able to log in, ignore zero results in the Search
window, then go to the Settings window. There is little sense in having users without the “ADMIN”
permission, due to absent studies in the Search window.
• (Option 2) Add the “ADMIN” permission to authorization.defaultHisPermissions.
Remember that all users will then be able to change MedDream settings and might thus interfere
with each other’s work. As a short-time measure, however, this option might still be more attractive
than the first one.
• (Option 3) Add the “USER_SETTINGS” permission to authorization.defaultHisPermissions.
Afterwards every user will be able to change his own copy of the settings file, and will need
administrator’s help to get the common settings back.
3. Edit application.properties file and update the options related to the plugin “FileSystem”. The
documentation below is for plugin version 7.0.0.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
type=FileSystem
Always set this to FileSystem.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
id=File-System-Plugin
Any alphanumeric string that identifies this plugin instance.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
rootDirectory=C:\\dicoms\\files
Full path to the base directory below which the DICOM files can be found.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].maxDepth=1
(optional) The number of subdirectories traversed when collecting files. Minimum allowed
value and default value is 0.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
cacheMaxSize=1000
(optional) Maximum number of studies in the in-memory cache. Minimum allowed value is
1, default is 1000.
• Example: com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].
cacheMaxAgeSec=7200
(optional) Maximum age, in seconds, of study records in the in-memory cache. Minimum
allowed value is 1, default is 7200 (2 hours).
The actual value might appear higher as record expiration is triggered by a write activity. If
new studies aren’t opened, then memory usage will stay unchanged.
4. Test the functionality by browsing to http://127.0.0.1/?file=PATH_TO_YOUR_FILE
For example, the directory C:\PACS\dcm4chee\server\default\archive contains DCM4CHEE
2.x archive tree, with deeper levels named like year\month\day\hour\.... This directory
is specified by rootDirectory. Then PATH_TO_YOUR_FILE could be 2012/2/4/0/43D7AA94/
2569DF62/9242C40A.
The “FileSystem-Non-Dicom” plugin allows to view directories with non-DICOM files in a fashion similar to the
traditional “filesystem” mode. A directory always results in a single study. Every file there appears as a series
with a single viewable object. Patient demographics and other metadata must be provided in a dedicated JSON
file.
There is no indexing, too, therefore the Search window can not be used.
MedDream is opened with a full path to a directory. The legacy “unsafe” method via /?file=. . . is not supported
so far, one must use token-enabled integration. Example token:
{
"items": [
{
"studies": {
"file" : "f:/tmp/study49405968726",
"storage": "fs2"
}
}
]
}
Viewable objects are files with extensions “png”, “bmp”, “jpeg”, “tiff”, “pdf”, “mp4”, “txt”. Files are sorted by name
and are displayed in this order. Filtering by name pattern or extension is not supported. Any subdirectories
will crash the plugin.
The metadata file must be named study-patient.json. Example contents:
{
"date": "2021-10-04",
"time": "14:36:30",
"description": "Second opinion (scanned document)",
"patientName": "John Doe",
"patientId": "123",
"sensitive": false,
"restricted": false,
"dob": "1975-04-12",
"gender": "M"
}
The fields “sensitive” and “restricted” are reserved in MedDream 8.1.0+. The value “true” will cause specific
behavior in later versions, and should not be used until then to avoid surprises.
The Modality attribute (visible in, for example, the Export window) is always set to “nonDicom”. However the
Export window, Forward window and some other functions do not work with non-DICOM studies.
The plugin currently caches some data until application restart, for every unique value of the “file” parameter.
Contrary to the FileSystem plugin, the same directory with updated content will not be rescanned. You must
use unique values of “file” every time (for example, generate the directory name randomly).
Do not set searchApiEnabled or documentApiEnabled in plugin configuration to false, as this plugin can’t be
combined with others, even with other plugin instances of the same type.
This plugin supports a custom HIS integration parameter “file”. Due to architectural shortcuts, it also supports
the ubiquitous parameter “study”. But, the latter is not intended for HIS integration, its value is random and
becomes unusable after restarting the JAR.
1. Perform steps in the 5.1.1 Essential configuration and the first run chapter.
1. Configure the HIS integration in application.properties file:
spring.profiles.include=auth-his
authentication.his.token-service-address=http://127.0.0.1:8082/v2/validate
#authorization.defaultHisPermissions=USER_SETTINGS
#authorization.defaultHisPermissions=ADMIN
spring.profiles.include=auth-pacsone,auth-his
authentication.his.valid-his-params=study
authentication.his.maxObjects=2
#authentication.his.useSameSession=true
(continues on next page)
spring.profiles.include=auth-pacsone,auth-his
authentication.his.valid-his-params=study,accnum
authentication.his.maxObjects=2
#authentication.his.useSameSession=true
#authentication.his.patient-integration-open-studies=false
authorization.defaultHisPermissions=EXPORT_ARCH,DOCUMENT_VIEW,BOUNDING_BOX_VIEW
spring.profiles.include=auth-pacsone,auth-his
authentication.his.valid-his-params[0]=patient,accnum
authentication.his.maxObjects=2
#authentication.his.useSameSession=true
#authentication.his.patient-integration-open-studies=false
authorization.defaultHisPermissions=EXPORT_ARCH,DOCUMENT_VIEW,BOUNDING_BOX_VIEW
spring.profiles.include=auth-pacsone,auth-his
authentication.his.valid-his-params[0]=study
authentication.his.valid-his-params[1]=patient,accnum
authentication.his.valid-his-params[2]=patient
authentication.his.valid-his-params[3]=storage
authentication.his.maxObjects=2
#authentication.his.useSameSession=true
#authentication.his.patient-integration-open-studies=false
authorization.defaultHisPermissions=EXPORT_ARCH,DOCUMENT_VIEW,BOUNDING_BOX_VIEW
(Formally the first example needs ...valid-his-params[0]=study, too. Luckily “[0]” is optional in this situation.)
The second example allows either “study” or “accnum” in the same installation. The third one defines a
combination of “patient” and “accnum” – not the same as either “patient” or “accnum”. The fourth contains
multiple parameters/combinations at once, and also allows to specify a particular PACS plugin via the “storage”
parameter.
The “maxObjects” parameter is zero by default, which means no limit and no protection against excessive amount
of studies.
The “useSameSession” parameter allows to have multiple viewer windows during “unsafe” HIS integration. By
default, a newly opened viewer window also replaces the session, therefore a window from the earlier session
may get “Access denied” errors.
Warning: The “storage” parameter is treated as optional, and is silently ignored if not enabled in valid-his-
params.
If missing or ignored, MedDream searches for objects via all available PACS plugins.
MedDream can also be integrated via its Communication API – a JavaScript-based wrapper over
the legacy/token URL method. See the Communication API specification; you can obtain it from
[email protected].
There is a third method where the image-displaying part of the frontend is added to your application as a React
component, and you implement all buttons by yourself. See the Viewport API specification, also available from
[email protected].
5. Deployment
This chapter is dedicated to PACS-independent part of the deployment. Normally you should start reading at
support for a specific PACS under 3 Integration with PACS, as those parts refer to this chapter anyway.
In case of Linux, this chapter assumes that the user has root permissions and appropriate part of MedDream
installation archive was extracted into /opt/meddream (the file /opt/meddream/MedDream-*.jar exists).
5.1. Configuration
Note: During an upgrade it’s recommended to use application.SAMPLE.properties (shipped with MedDream)
as a template and update every setting based on contents of your old configuration file. This will prevent
misunderstandings like parameters renamed or removed between versions.
server.port = APPLICATION_PORT
Allows to choose a different port if the default one is occupied. Example: server.port=80.
• Under Linux, FFmpeg installation is required to create video thumbnails and convert some less-
supported formats.
com.softneta.thumbnails.ffMpegExecutable = PATH_TO_FFMPEG
The default value is a simple name of the executable, ffmpeg. In most cases it is enough
under Linux.
Starting from 8.0.0, under Windows the value “ffmpeg”, even if configured explicitly, is
automatically replaced with “./sys/ffmpeg/ffmpeg.exe”. If the installation was relying on PATH
earlier, then one can specify the value “ffmpeg.exe” to avoid the mentioned replacement. The
best choice is to update this parameter with a full path to ffmpeg.exe.
• wkhtmltopdf (https://wkhtmltopdf.org/downloads.html) is required to include reports in exported
studies. You can skip this if reports aren’t used at all, or aren’t included during export.
Under Linux the binary is normally found in PATH. Under Windows the recommended install
locations are C:\Program Files\wkhtmltopdf and C:\Program Files (x86)\wkhtmltopdf; you can
also download the 7z Archive and just copy the EXE file to sys/report/wkhtmltopdf.exe. If your
system must use a different location, then you can specify it in application.properties:
com.softneta.export.htmlToPdf = D:/wkhtmltopdf
com.softneta.export.htmlToPdf = /opt/wkhtmltopdf
At this point it should just start up without errors, and the message “Application . . . started” will eventually
appear.
The login form at http://localhost:APPLICATION_PORT/ is disabled by default (results in a “403 Forbidden”
message when application.properties is composed from scratch) unless 5.1.3 Built-in authentication and
authorization is configured. On the other hand, application.SAMPLE.properties already configures the “in-
memory” authentication by default, with a predefined password. As the optimal method might be PACS-
dependent, you can configure it a bit later, together with the plugin for a particular PACS.
1. FFmpeg is required in order to display thumbnails of MPEG2 DICOM files and non-BD-compatible MPEG4
videos (Transfer Syntax UID 1.2.840.10008.1.2.4.102). If your distribution does not provide ffmpeg, avconv
package may be used. In that case a symlink to avconv binary is required:
ln -s /usr/bin/avconv /usr/bin/ffmpeg
2. To display non-BD-compatible MPEG4 videos (Transfer Syntax UID 1.2.840.10008.1.2.4.102), latest
version of FFmpeg might be required.
3. If Java application will run under a non-root user, then adjust file system permissions:
Running Java application as root is OK for initial tests, however in production environment it
should run under some limited user instead, ideally the one who can access all DICOM files in
read only mode. A compromise would be to run the JVM under the same user as the PACS
process.
This adjustment step makes sure that a process running under a limited user can access its files,
especially the ones created earlier under name of root. In the simplest case you can examine
the log file after starting the process under a different user, as even the log file will likely be
non-writeable.
5.1.2. System.json
The file system.json (sys/settings/system.json by default) is automatically created if missing when the Java
application starts. Several key features require this file to be updated during installation; the application must be
restarted afterwards.
An example of the entire file is shown below. When updating, take care to preserve the syntax (quotes, commas,
brackets, etc.); a text editor with JSON syntax checking is recommended.
{
"disableMultiFrameVideoAutoLoad": false,
"features": {
"patientHistory": false,
"keyObjectAndPresentationStateQuickSave": true,
"keyObjects": true,
"presentationState": true,
"searchSettings": true,
"viewerSettings": true,
"reportSettings": true,
"hangingProtocolsSettings": true,
"export": true,
"archive": true,
"search": true,
(continues on next page)
• disableMultiFrameVideoAutoLoad: false
(reserved) Disables multiframe and video autoload. Used for automated testing purposes, do
not change this setting.
• patientHistory: false
If true, the viewer window will load patient history and the corresponding button is enabled.
Disabled by default.
• keyObjects: true
The viewer window will load key objects.
• keyObjectAndPresentationStateQuickSave: true
The viewer window will display the Key Object And Presentation State Quick Save button.
• presentationState: true
Note: With true, you must also enable the liveshare Spring profile and configure the legacy
HIS integration with at least the parameter “study”, in application.properties:
spring.profiles.include = liveshare,auth-his
authentication.his.valid-his-params = study
• “hangingProtocols”: “V1”
Globally enable or disable the Hanging Protocols functionality.
In MedDream 8.3+ the allowed values are "V1" (same as true), "V2", "NONE" (same as false).
However “V2” should not be used as functionality isn’t ready for general public yet.
• openTabsTrackingMethod: “NONE”
Possibility to enable more strict tracking of open tabs. Ideally, when all tabs are closed by
pressing the “X” button, MedDream should log off as if “Logoff” were chosen from the menu.
The string “SOCKETS” enables websocket-based tracking. It is also needed to add track-tabs
to spring.profiles.include (application.properties).
Note: There is a grace period of 10 seconds. If you open MedDream once more during that
time, then the session remains.
Without this period, a single tab could get logged off even when reloading its contents (pressing
the F5 button).
• prepareInstances: false
If true, the series preload will make sure each image is prepared. This might increase
performance up to 20%.
• batchImageRequests: true
Enables batch downloading of image pixels; this may result in multiple images per request and
therefore reduce the overhead. Assign false for pre-7.7.0 behavior.
• thumbnailsPerSeries: “FIRST”
By default MedDream 7.7.0+ attempts to speed up loading of CT, PT and MR studies by
displaying only the summary thumbnail in every series. Assign “ALL” for pre-7.7.0 behavior.
Another possible value is “MIDDLE”. It requires com.softneta.preparation.thumbnailCreation =
all. Unfortunately, as the preparation is performed per-instance and as soon as possible (without
waiting until the entire study is sent), it is not feasible to determine which object is at the middle;
all thumbnails must be available for thumbnailsPerSeries=MIDDLE.
• summaryThumbnailsFor: [“CT”, “MR”, “PT”, “NM”]
List of Modality values to which the thumbnailsPerSeries setting applies. Before 7.9.0 the
values CT”, “PT” and “MR” were hardcoded in the frontend.
• preloadSeries: “OFF”
When that summary thumbnail is enabled, then it can also trigger preload of its series. “NONE”
– no preload, “OFF” – the end user must click on the summary thumbnail to trigger the preload,
“ON” – the preload starts automatically.
• boundingBoxAnnotations: true
Globally enables the Segmentation toolbar button and the Bounding Box tool below it. The user
must also have the BOUNDING_BOX_EDIT permission to see the button. Furthermore, the
button is disabled by default in the Settings window (Viewer / Toolbar properties / Segmentation
Tools / Bounding Box).
• viewToClipboard: “IMAGE”
Functionality of the button “Copy image to the clipboard”. “IMAGE” – the button copies an
image of the active viewport (with burned-in Info Labels, measurements, etc.); “JSON_IMAGE”
– it copies a certain JSON structure with measurements and Base64-encoded image as in the
“IMAGE” case; “NONE” – the button is not displayed.
• pngPSToClipboard: “NONE”
Functionality of the button “Export original image to the clipboard”. “IMAGE” – the button copies
the active image of original size and without any burned-in information (as with “PNG” and
“Active Image” in the Export window); “JSON_IMAGE” – it copies a certain JSON structure with
measurements and Base64-encoded image as in the “IMAGE” case; “NONE” – the button is not
displayed.
Note: Additional requirements for displaying the button are: 1) modality DX, CR, RX, CT or MR;
2) not a video or multiframe file.
• viewToDICOM: true
Globally enable the button “Save viewport content as secondary capture DICOM”. The button
also needs the COPY_TO_DICOM permission. If one or another is missing, then the button is
not visible and only secondary capture images saved earlier can be accessed.
This feature is needed by the Montage functionality, too.
• mistMpr3D: true
Globally enable or disable the 3D view (4th viewport) of the “Oblique MIST” functionality.
• clearCache: true
Globally enable or disable the “Clear cache” functionality. When enabled, the user must also
have the CLEAR_CACHE permission.
• measurementsPropagation: true
Show copy/paste buttons when creating a measurement. Enabled by default.
• digitalSubtraction: “NONE”
Enable the Digital Subtraction Angiography functionality. “NONE” (default): the functionality is
disabled. “AUTO”: the functionality is applied automatically. “MANUAL”: a button is displayed if
the images contain necessary information, and the end user can start DSA manually.
• blackListedSopClasses: [“1.2.840.10008.5.1.4.1.1.66”]
Thumbnails of images with these SOP Classes will not be shown in the viewer.
This list is appended to a hardcoded list of non-image objects from DICOM Standard. (By the
way, the above . . . 1.1.66 SOP Class is already there.) Main purpose of this setting is to hide any
Private SOP Classes not known in advance.
• storeScpIp: “127.0.0.1”
• storeScpIp: “192.168.200.65”
Destination IP address (or hostname) for the Forward function. Only for
com.softneta.meddream.dcmsnd.forwardingMethod=native.
• storeScpPort: 4242
• storeScpPort: 5678
Destination TCP port for the Forward function. Only for
com.softneta.meddream.dcmsnd.forwardingMethod=native.
• storeScpAet: “PACS”
• storeScpAet: “OSIRIX”
Destination AE Title for the Forward function. Will be visible in the Forward window.
• description: “An example destination for Forward”
Note: In MedDream before 7.8, this setting was called seriesParallelStreams and was
applicable to batchImageRequests=true only.
• maximumPixelStreams: 15
Number of parallel streams to download image pixels. Applies to all kinds of single-frame pixel
requests: the legacy /pixels (for batchImageRequests=false) and the recently introduced /multi-
pixels (for batchImageRequests=true).
In MedDream before 7.8, this setting was named parallelStreams and was applicable
to batchImageRequests=true only.
• maximumMultiFrameStreams: 4
Number of parallel streams to download multi-frame pixels. Applies to any value of
batchImageRequests.
Note: In MedDream before 7.8, this setting was named multiFrameParallelStreams and was
applicable to batchImageRequests=true only.
• batchSizeMb: 5
Image pixel downloads are grouped so that the combined estimate of download size doesn’t
exceed this setting (if batchImageRequests is not false).
• multiFrameBatchSizeMb: 2
Equivalent of batchSizeMb for downloading frames of a multi-frame image (if
batchImageRequests is not false).
• workersConfig: . . .
Number of browser threads. “maxWorkers” are for decompression of pixel data,
“maxSegmentationWorkers” – for the segmentation function. Values in percent are relative to
actual number of CPU threads at a particular client machine.
• cacheSupervisorConfig: . . .
Monitors caching of images at the frontend. Every runFrequencyInSec seconds images not
displayed in any viewport are marked for removal, and those that were marked previously, are
removed from memory.
Specify true for enabled to enable this functionality.
• scrollingConfig: . . .
The vertical slider is displayed on the image if its Modality or SOP Class attribute matches a value
listed here. The default is a few modality values and an empty list of classes, and corresponds
to behavior of earlier versions where those modalities were hardcoded.
• notificationsConfiguration.autoCloseAfterSec: 10
A message is displayed on screen for this number of seconds, then hidden away.
• personNameConfiguration: . . .
Defines the format of person names (currently Patient Name and Referring Physician Name
attributes). In 8.0.0, some plugins (QR, Dicomweb, PacsOne, DCM4CHEE 2.x and 5.x)
were updated to return person names in DICOM standard format – with ^ separators, all 5
components, all 3 component groups.
formatIn provides a pattern for identifying name components in the input string, based on
separator positions. It applies to every component group. The default value (used instead
of null or empty string) is "{lastName}^{firstName}^{middleName}^{prefix}^{suffix}" and
complies to the Standard.
In general, a component consumes the part of the input string up to the next separator. When
there are not enough separators, then some component will consume all remaining input.
Results will be unexpected if the components were entered in a non-compliant manner at the
modality, like “John Doe^Dr.” instead of “Doe^John^^Dr.”; however, if all modalities behave that
way, a corresponding formatIn could adapt to it.
formatOut is a format string for every component group of the result. The default value
(used instead of null or empty string) is "{prefix} {lastName} {firstName} {middleName}
{suffix}".
The simplest use case is to change the component order via formatOut – for example,
"{firstName} {lastName}".
After updating to 8.0.0, compliant plugins listed above will produce names with prefixes at the
beginning, like “Dr. Doe John” instead of “Doe John Dr.”. Furthermore, some plugins are now
returning all components instead of just last and first name. Both issues can be worked around
with formatOut. The behavior won’t differ with non-compliant plugins like Orthanc, as they use
the legacy space-delimited name format and {lastName} in formatIn gets everything.
• searchHistoryByPatientId: true
When true, MedDream uses the traditional patient history search key – a single Patient ID
attribute. When false, the search key is a logical AND of attributes Patient Name, Patient’s
Sex and Patient’s Birth Date.
Warning: As of 8.1.0+, the value “false” is only for DCM4CHEE 2.x and 5.x PACS plugins.
Other plugins might become confused and won’t return any results; this also includes Multi-
PACS setups where DCM4CHEE plugins are mixed with other ones.
• dontAutoOpenTheseAnnotations: [“Lunit”]
Names of annotations that won’t be opened automatically when “Auto open annotations” is
enabled in the Settings window. The intended use case is filtering of annotations added by
automated diagnosis systems, while annotations created manually would still open automatically.
Empty by default.
• fusionConfig.modality: [“CT”, “MR”, “PT”]
• fusionConfig.sopclass: []
In general Fusion is possible between any modalities in the same frame of reference but their
values must be configured first. By default they’re CT, MR or PT. This can be changed by the
“modality” setting.
You can also configure a SOP Class UID whitelist in the “sopclass” setting. Both whitelists are
combined with logical OR (if both are empty, then Fusion isn’t allowed at all).
• segmentationConfig: . . .
“smartPaintPreloadOptions” can be “wait-for-toolbar” (default) or “load-on-open”. The latter will
enable parsing of probability-based annotations as soon as possible.
“messagingLevel” can be “minimal” (default) or “medium”.
• instancesProgressivePreloadConfig.preloadCount: 5
• instancesProgressivePreloadConfig.supportedModalities: [“CT”, “MR”, “PT”, “NM”]
• instancesProgressivePreloadConfig.supportedSOPClasses: []
• instancesProgressivePreloadConfig.enableSeriesManualPreload: true
When loading a particular image, also load up to preloadCount images before and after it. This
behavior, however, applies only if Modality attribute matches an entry in supportedModalities, or
SOP Class UID matches an entry in supportedSOPClasses.
enableSeriesManualPreload=false disables the “cloud” icon in the series header, however only
for series where supportedModalities or supportedSOPClasses match.
• windowPosition: [{“name”: “name1”, “width”: width1, “height”: height1},{“name”: “name2”, . . . },. . . ]
Override default widths and/or heights of GUI windows. When configuring only the width, you
can target a group of windows; for example, “modalSmallWidth” targets Register, About and
many other windows, while “register” is for the Register window only.
Dimensions are in pixels. Unspecified or zero means “default” and is ignored. Minimum height
is 300, smaller values are also ignored. There is no minimum width, you can use the default
below as a ballpark value; significantly smaller values were not tested and might result in
incorrect appearance or behavior.
MedDream supports a few universal authentication/authorization methods. They can be used when instructions
for a particular PACS integration do not offer a dedicated (more proper) method.
Most methods are designed for the interactive login. As a result, the login form can be opened only when a
particular method is chosen (for example, spring.profiles.include = auth-pacsone).
For authorization you can choose from the following list of permissions:
• ADMIN – Settings and Register;
• SEARCH – the Search window;
• PATIENT_HISTORY – Patient History;
• UPLOAD_DICOM_LIBRARY – Share (Share via DICOM Library window);
• EXPORT_ISO – the Export function related to “Download” and “Burn”;
• EXPORT_ARCH – the Export function related to “Save”;
• FORWARD – the Forward function;
• REPORT_VIEW – read-only access to Reporting function;
• REPORT_UPLOAD – full access to Reporting function (does not include “remote reports”);
• ANONYMOUS_VIEW – on-the-fly anonymization of visible patient data (except PDFs, SRs and forwarded data);
• DOCUMENT_VIEW – ability to view Structured Report and PDF documents (however they are forwarded
regardless of this permission);
• BOUNDING_BOX_VIEW – allows display of annotations saved by Segmentation > Bounding Box;
• BOUNDING_BOX_EDIT – full access to Segmentation > Bounding Box and visibility of this button (however
there also is a global setting, features.boundingBoxAnnotations, in system.json);
• FREE_DRAW_VIEW` – allows display of annotations saved by Segmentation > Free Draw;
• FREE_DRAW_EDIT – full access to Segmentation > Free Draw and visibility of this button (subject to
features.boundingBoxAnnotations, too);
• SMART_DRAW_VIEW allows display of annotations saved by Segmentation > Smart Draw;
• SMART_DRAW_EDIT – full access to Segmentation > Smart Draw and visibility of this button (subject to
features.boundingBoxAnnotations, too);
• COPY_TO_DICOM – display of the button “Save viewport content as secondary capture DICOM” (there is also
a global setting, features.viewToDICOM=true, in system.json) and support of Montage functionality;
• USER_SETTINGS – allows to save settings to a customized global.json. Without this permission, a
customized global.json can only be read;
• CLEAR_CACHE – allows to use the “Clear cache” function (there also is a global setting, features.clearCache,
in system.json);
• SHORTCUTS_EDIT – allows to edit the shortcuts (this permission is required even for users that have ADMIN);
• HANGING_PROTOCOLS_EDIT – allows editing of hanging protocols for user that don’t have ADMIN (there is
also a global setting, features.hangingProtocols, in system.json);
• PACSONE_VIEW_ONLY_PUBLIC – an opposite of the legacy VIEW_PRIVATE if the message “Limited view
access” is still required.
Warning: When upgrading to 8.2+, it is advised to remove obsolete permissions 3D_RENDERING and
VIEW_PRIVATE from all possible places of configuration:
• authorization.defaultLoginPermissions setting
• authorization.defaultHisPermissions setting
• authorization.users[].role settings
• authorization.remapRoles.* settings
• embedded authentication database for the auth-meddream profile
For some time MedDream will gracefully ignore this permission if left in configuration. However in the future
the value will become really unknown and might crash the backend.
Warning: DOCUMENT_VIEW must be present for pre-7.5.1 functionality. Currently MedDream does not
support permissions of “deny” type (existing ones are of “grant” type), therefore it is not possible to grant
DOCUMENT_VIEW for all users and afterwards deny for a few ones.
Warning: Take caution with DOCUMENT_VIEW together with ANONYMOUS_VIEW. Anonymization of PDFs and
SRs is not supported, therefore DOCUMENT_VIEW will leak sensitive patient data to users who do not see it
normally.
Absence of DOCUMENT_VIEW only prevents interactive display and Export of this data. Forward still shares all
DICOM objects in the study and so might present a workaround for users who don’t have this permission.
Note: 8.2+ contains an inverted logic regarding the now obsolete VIEW_PRIVATE permission. It behaves as
if that permission is always present; the message “Limited view access” is automatically displayed only when
using Pacsone plugins with auth-pacsone and the account configured in PacsOne user administration doesn’t
have the “View private” privilege.
It is important to remember that in all other situations, like authentication other than auth-pacsone, or using a
non-PacsOne plugin, that message was misleading (and still is): other plugins do not implement a corresponding
filter, while other authentication types do not support First Name and Last Name of the currently logged in user,
that are needed by the filter in PacsOne plugin.
For an unlikely event where the end users are expecting this message despite usage of a different authentication
or a non-PacsOne plugin, you can get it back by adding the PACSONE_VIEW_ONLY_PUBLIC permission for
corresponding users.
Provides both authentication (username/password) and authorization (permissions). All this data must be
entered into application.properties, in plain text form.
The spring.profiles.include setting must include auth-inmemory. 7.5.2+ does this by default and includes a
single user named “demo”, with a password known in advance that must be changed during the installation.
Elements of authentication.inmemory.users[] describe the credentials. Elements of authorization.
users[] link to credentials and list the permissions; the per-user accessibleStorages setting can restrict the
list of allowed Multi-PACS plugin instances (beware: values that don’t match the .id parameter of a configured
plugin will stop application loading). authorization.defaultLoginPermissions lists permissions common to
everyone.
The parameter accessibleStorages can also be used at group level. The group is referenced by
authorization.users[].groups and defined in authorization.groups[].
Example with two users:
spring.profiles.include = auth-inmemory
authentication.inmemory.users[0].userName = user1
authentication.inmemory.users[0].password = pass1
authentication.inmemory.users[1].userName = user2
authentication.inmemory.users[1].password = pass2
authorization.users[0].userName = user1
authorization.users[0].role = ADMIN,SEARCH,DOCUMENT_VIEW
authorization.users[0].groups = administrators
authorization.users[1].userName = user2
authorization.users[1].role = SEARCH,ANONYMOUS_VIEW
authorization.users[1].accessibleStorages = PacsOneRouter,MainArchive
authorization.defaultLoginPermissions = PATIENT_HISTORY,REPORT_UPLOAD,\
UPLOAD_DICOM_LIBRARY
authorization.groups[0].name = administrators
authorization.groups[0].accessibleStorages = PacsOneRouter,MainArchive,ResearchPacs
Keeps credentials and permissions in a built-in H2 database. Passwords are salted and hashed.
There is no GUI so far, management involves running SQL commands in the H2 Console.
After fresh installation of MedDream, make sure that application.properties contains
spring.profiles.include = auth-meddream
Note: By default, application.SAMPLE.properties enables auth-inmemory and this is done on another line.
There is no error message if you assign to spring.profiles.include multiple times, and the outcome might be
counter-intuitive. Make sure to comment the unneeded line out.
Unlike in other mechanisms, the per-user accessibleStorages setting can’t be stored in the database.
Verifies credentials against an LDAP server (you can use third-party tools to manage credentials and groups).
Mapping between user’s LDAP groups and MedDream permissions is configured in application.properties. The
latter can also append permissions to individual users.
The spring.profiles.include setting must include auth-openldap or auth-activedirectory when using
the corresponding server. There also is a variant of AD for servers with mandatory GSSAPI/Kerberos,
auth-kerberosldap.
The main setting is authentication.ldap.url: hostname, port and base DN. For SSL you need to use “ldaps://”
for the protocol, and likely a different port (for example, 636). Other settings depend on the profile.
Example for OpenLDAP:
spring.profiles.include = auth-openldap
authentication.ldap.url = ldap://MY-SERVER:389/ou=DEPT-NAME,dc=COMPANY-NAME
authorization.defaultLoginPermissions = SEARCH,EXPORT_ARCH,EXPORT_ISO,PATIENT_HISTORY,\
UPLOAD_DICOM_LIBRARY,DOCUMENT_VIEW
authorization.remapRoles.DOCTORS-GROUP-NAME = CLEAR_CACHE
authorization.remapRoles.ADMINS-GROUP-NAME = ADMIN
authorization.remapRoles.TECHNICIANS-GROUP-NAME = FORWARD
authorization.users[0].userName = USER-NAME-1
authorization.users[0].role = ADMIN
authorization.users[1].userName = USER-NAME-2
authorization.users[1].role = FORWARD,REPORT_UPLOAD,BOUNDING_BOX_EDIT
authorization.users[1].accessibleStorages = st3
spring.profiles.include = auth-activedirectory
#spring.profiles.include = auth-kerberosldap
authentication.ldap.url = ldap://MY-SERVER:389/ou=DEPT-NAME,dc=COMPANY-NAME
authentication.ldap.bindUserDn = cn=MEDDREAM-APP,ou=SERVICE,ou=DEPT-NAME,dc=COMPANY-NAME
authentication.ldap.bindUserPassword = MEDDREAM-APP-PASS
authentication.ldap.userSearchBase = ou=USERS
authentication.ldap.groupSearchBase = ou=USERS
authorization.defaultLoginPermissions = SEARCH,EXPORT_ARCH,EXPORT_ISO,PATIENT_HISTORY,\
UPLOAD_DICOM_LIBRARY,DOCUMENT_VIEW
authorization.remapRoles.DOCTORS-GROUP-NAME = CLEAR_CACHE
authorization.remapRoles.ADMINS-GROUP-NAME = ADMIN
authorization.remapRoles.TECHNICIANS-GROUP-NAME = FORWARD
authorization.users[0].userName = USER-NAME-1
authorization.users[0].role = ADMIN,REPORT_VIEW
authorization.users[1].userName = USER-NAME-2
authorization.users[1].role = FORWARD,REPORT_UPLOAD,BOUNDING_BOX_EDIT
authorization.users[1].accessibleStorages = st3
To authenticate, MedDream binds to bindUserDn using bindUserPassword, searches for a user object at or below
ou=USERS (empty userSearchBase is not allowed) with a hardcoded filter (sAMAccountName=LOGIN-NAME), then
binds to the found DN using the password from the login form.
Then it extracts group names from this user object. Its attributes memberOf (hardcoded) are expected to contain
group DNs which start with cn=GROUP-NAME,.... Due to technical limitations, the user object found earlier
is not reused – a second search is performed at or below groupSearchBase (should obviously be equal to
userSearchBase) with the same hardcoded filter (sAMAccountName=LOGIN-NAME).
As with OpenLDAP, authorization.remapRoles.* provide permission sets for entire groups, while
authorization.users[] can add more permissions to individual users.
If your server demands GSSAPI, just use the “auth-kerberosldap” profile instead.
Since 8.3 any kind of LDAP storage can authenticate only users that belong to specified groups:
Traditionally, groups in MedDream are used only to map permissions and do not participate in authentication.
This parameter is empty by default and no group membership is enforced. Two-dimensional syntax similar to
validHisParams is supported: the first level separates elements with logical OR, the second level – with logical
AND.
Note: By default, application.SAMPLE.properties enables auth-inmemory and this is done on another line.
There is no error message if you assign to spring.profiles.include multiple times, and the outcome might be
counter-intuitive. Make sure to comment the unneeded line out.
Warning: Spaces embedded in role names are ignored. For example, “Super Users” and “SuperUsers” will
be treated as the same role.
5.1.3.4. SAML
Credentials entered in the login form will be validated by an external identity provider.
Supported endpoints are /saml2/authenticate/okta. See https://developer.okta.com/code/java/spring_
security_saml for details.
spring.profiles.include = auth-saml
spring.security.saml2.relyingparty.registration.okta.assertingparty.metadata-uri =\
https://dev-0731725.okta.com/app/exk3k4dxuhko35exg5d7/sso/saml/metadata
authorization.defaultLoginPermissions = SEARCH,EXPORT_ARCH,EXPORT_ISO,PATIENT_HISTORY,UPLOAD_
˓→DICOM_LIBRARY
authorization.remapRoles.doctor = CLEAR_CACHE
authorization.remapRoles.administration = ADMIN
authorization.remapRoles.assistant = FORWARD
User roles are taken from the SAML attribute “memberOf”. When using them, authorization.remapRoles.* is
needed for mapping to MedDream permissions.
Generic authentication against a DBMS server (you can use third-party DBMS tools to manage credentials).
Internal MedDream permissions are assigned to users in application.properties.
Example with two MySQL users:
spring.profiles.include = auth-db-connection
authentication.database.driverClassName = com.mysql.jdbc.Driver
authentication.database.jdbcUrl = jdbc:mysql://127.0.0.1:3306/pacs2
authorization.defaultLoginPermissions = EXPORT_ARCH
authorization.users[0].userName = user1
authorization.users[0].role = ADMIN,SEARCH,DOCUMENT_VIEW,REPORT_VIEW,BOUNDING_BOX_VIEW
authorization.users[1].userName = user2
authorization.users[1].role = SEARCH,REPORT_UPLOAD,BOUNDING_BOX_EDIT
authorization.users[1].accessibleStorages = st3
Note: By default, application.SAMPLE.properties enables auth-inmemory and this is done on another line.
There is no error message if you assign to spring.profiles.include multiple times, and the outcome might be
counter-intuitive. Make sure to comment the unneeded line out.
In demo installations it is sometimes desirable to have the login form automatically filled with some working
credentials.
For that it is necessary to patch md5/index.html. Find the final </body></html> and insert the following before
it:
<script>
window.autoFillLogin = { username: ACCOUNT_USERNAME, password: ACCOUNT_PASSWORD }
</script>
For example,
... src="js/md.main.min.7.5.1-47d313eb039c.js"></script>
<script>
window.autoFillLogin = { username: 'demo', password: 'demo' }
</script>
</body> </html>
Reports and attachments are saved into the same H2 database, sys/database/reportdb.*.
• The legacy option $attachment_upload_dir (config.php) is not implemented yet. Attachment contents are
always stored into the database.
• The structure is slightly different from the legacy “studynotes” and “attachment” tables. Access to legacy
tables, especially the ones updated by PacsOne GUI, is not possible even after configuring MySQL storage
instead of H2.
There are two attachment size limits that you might need to configure. MedDream will inform you which specific
limit was exceeded. The size of the largest file, and the total size of all files during the same upload operation,
are configured separately:
spring.servlet.multipart.max-file-size=1MB
spring.servlet.multipart.max-request-size=10MB
Print templates are supported like in 7.1 MedDream and existing ones might work without modification. The file
sys/report/default.html is an example with all supported value placeholders. Adjacent files CR.html, XC.html etc
(named after the first modality value in the study), if present, will be used for studies with particular modalities.
Stamps in print templates are expected in form of files sys/report/stamp/LOGIN_NAME.jpg.
When Reporting is used in HIS integration mode (including integration into PacsOne web interface), MedDream
currently assigns the same user identity in all saved reports. It can be configured by
authentication.his.username=his-user-name
Please contact [email protected] for the migration script. It will copy the MySQL database records (and
content of externally stored attachment files) to a .sql file, which can afterwards be imported via H2 Console.
This task was sometimes needed in PHP-based MedDream and is now possible in 7.5.2+, too.
Open the H2 Console in the browser (for details, see 5.1.10 Opening the H2 Console). Open
sys/database/reportdb there (example URL: jdbc:h2:file:/C:/PROGRA~1/PacsOne/php/meddream/sys/
database/reportdb) with username “sa” and no password.
View contents of the TEMPLATE table. Add the WHERE user='SOURCE_LOGIN_NAME' clause (with real username)
to the autogenerated SQL statement and confirm that the needed records exist.
Replace the SQL statement with the following, then change DESTINATION_LOGIN_NAME and
SOURCE_LOGIN_NAME to real values and execute:
In a similar fashion, view the TEMPLATE table again and confirm that DESTINATION_LOGIN_NAME now
has the needed records, too. At this point a refreshed MedDream Reporting window should also display the
corresponding templates.
In general, the settings spring.h2.console.* are also needed for editing the auth-meddream database, while
authentication.manager.* are also needed for editing auth-meddream and for various investigations via /manage
endpoint. If these tasks are not planned immediately, then all four settings should be commented out for security
after you finish with templates.
H2-based report storage works out of the box and is adequate for small institutions. However heavy use of
reports (especially with attachments), or the need to access them from third-party software, might call for a
different database engine. MedDream 7.6.0+ supports MySQL as an alternative.
We strongly recommend to create a new database dedicated to reports, in order to avoid name conflicts with
existing tables.
Relevant settings in application.properties:
report.datasource.url=jdbc:mysql://DB_HOST:DB_PORT/DB_NAME
report.datasource.driverClassName=com.mysql.cj.jdbc.Driver
report.datasource.username=USER_LOGIN
report.datasource.password=USER_PASSWORD
Missing tables are created automatically when MedDream starts. Table structure might be automatically updated
during the first run of a newer MedDream version. The user name USER_LOGIN must initially refer to a
privileged user – with ALL PRIVILEGES (or at least REFERENCES, INDEX, ALTER, CREATE, SELECT, INSERT,
UPDATE, DELETE), or similarly capable of manipulating the schema. Only after making sure that the entire
functionality of reports is working, you can downgrade to a less-privileged user (SELECT, INSERT, UPDATE,
DELETE are sufficient).
If you absolutely need to use an existing database, then plan carefully:
1. MAKE A DATABASE BACKUP before the first run with MySQL-based report storage, and from now on –
before the first run of a newer MedDream version;
2. names of MedDream-related tables are “report”, “template”, “attachment”, “report_attachment” and
“flyway_schema_history”. Make sure your schema does not already contain tables with these names.
For example, PacsOne uses the table “attachment” for its own purposes;
3. it is possible to assign new names to most tables except “flyway_schema_history” :
report.tableNames.report=NEW_REPORT_NAME
report.tableNames.attachment=NEW_ATTACHMENT_NAME
report.tableNames.template=NEW_TEMPLATE_NAME
report.tableNames.report_attachment=NEW_REPORT_ATTACHMENT_NAME
4. those custom table names are a critical piece of configuration. If you accidentally comment them out, or
specify the name of an existing third-party table, then your data is at danger! In the best case nothing
serious will happen to a foreign table but MedDream won’t be able to use it due to still incompatible
structure.
The “Remote reports” functionality requires custom works by the customer and has the following limitations:
• only the Query/Retrieve integration;
• report status available only after opening the study or in the Patient History window (not in the Search
window);
• operation is read-only (no editing, just display);
• supported content types are application/pdf, application/json, application/xml, application/xhtml+xml,
image/gif, image/jpeg, image/png, text/html, text/plain, text/xml.
It must be enabled in application configuration:
• specify features.remoteReports=true in system.json (incompatible with features.reports=true);
• add REPORT_VIEW permission for the user (REPORT_EDIT, however, will be ignored).
In the configuration of the QR plugin, a custom DICOM tag number needs to be specified:
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.report.tag=CUSTOM_
˓→DICOM_TAG_IN_DECIMAL
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.report.type=string
The PACS will receive this attribute as a return key, and should return a study-level attribute with this tag. If a
non-empty value is found in the response, then the plugin replaces it with the reportURL setting after filling the
placeholders {studyUid} and {storageId} (at least the first one should be present):
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].reportURL=http://127.0.0.
˓→1:8088/report?study={studyUid}&storage={storageId}
#com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].reportURL=/mnt/attached-
˓→reports/{studyUid}.pdf
reportURL can specify a custom endpoint that returns content of the report attached to the study. The URL
can be generic or RESTful. A GET request without authentication will be performed. If the URL doesn’t begin
with “http”, it is treated as a file system path and must be readable by the JVM process on the machine where
MedDream is installed.
Additional configuration (optional):
report.remoteReports.contentType=text/plain
report.remoteReports.proxyHost=172.30.55.1
report.remoteReports.proxyPort=8088
report.remoteReports.cacheMaxAgeSec=300
report.remoteReports.httpTimeout=5000
report.remoteReports.maxSize=1000000
The first step in getting the content type is to use the value returned by the server, or configured as file
name extension in reportURL when it specifies a file system path. If the server returned some type, or it
was successfully determined from the path, then it is validated against the list of supported types. Otherwise
(the server didn’t return the type, or detection has failed) the contentType setting is used (defaults to
“application/pdf”). The final value is added to the response from MedDream backend and the browser will
react correspondingly.
proxyHost and proxyPort are only used if both are provided and the port number is larger than zero.
If httpTimeout is larger than zero, it is used both as connection timeout and read timeout (in milliseconds). By
default there is no timeout.
A larger than zero maxSize imposes a size limit on downloadable or file system resource: there will be no
attempts to display a larger file.
If cacheMaxAgeSec is larger than zero, then a Cache-control: max-age=... header with this value is added to
the corresponding MedDream response (from backend to frontend). Might be required when MedDream itself is
being accessed via a caching proxy.
Some example configurations included in MedDream installation archive specify 1 GB, which is sufficient for
typical files.
In general, the application requires an amount of memory no less than the size of the largest DICOM file.
Use this as a ballpark figure, and add a generous overhead for simultaneous connections. Furthermore, up
to com.softneta.preparation.maxThreadCount files of the same study will be processed in the background
simultaneously, so this should be taken into account, too, when your studies contain multiple moderately-sized
files.
Experiments with a single connection show that a single 1.3 GB multiframe file opens rather slowly under a 2
GB memory limit and without problems under a 3 GB limit; consequently, 4 GB would be recommended in this
case.
The memory limit is configured by the Java option -XmxSIZE, where SIZE can use suffixes “M”, “G”, etc. (for
example, -Xmx1024M).
If the same value is also specified with -XmsSIZE, then performance might be better as no resources are wasted
while growing the heap – it’s always of this size. At least 2 GiB is recommended.
Furthermore, even with adequate -Xmx and -Xms values Java might still crash due to “OutOfMemoryError: Direct
buffer memory”. The solution is to configure a small limit (approx. 1 MiB) via jdk.nio.maxCachedBufferSize.
• When you are starting the backend from the console (during 5.1.1 Essential configuration and the first run,
or for a quick experiment with a stopped service), then just add -Xmx4G etc. as the first option. For example,
˓→com.sun.management.internal=ALL-UNNAMED --add-opens=java.base/jdk.internal.
˓→opens=java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED --add-opens=jdk.
˓→internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED --add-opens=java.base/sun.
˓→reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens=java.base/java.
˓→opens=java.base/java.time=ALL-UNNAMED --add-exports=java.desktop/sun.awt.
˓→image=ALL-UNNAMED org.springframework.boot.loader.PropertiesLauncher
˓→opens=jdk.management/com.sun.management.internal=ALL-UNNAMED --add-opens=java.
˓→base/jdk.internal.misc=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-
˓→opens=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED --add-opens=java.
˓→base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens=java.base/
˓→opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-
˓→desktop/sun.awt.image=ALL-UNNAMED org.springframework.boot.loader.
˓→PropertiesLauncher
(The last version allows Java to utilize 50% of available physical memory.)
• When the service is already set up, then you need to adjust the application command line in the
corresponding part of the installation. See the chapter 5.2 Running as a service for possible locations.
The single Tomcat web server port, server.port, can be configured for HTTPS instead of HTTP.
(Option 1) To create a self-signed certificate, you can use keytool from JRE:
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore path/
˓→to/keystore.p12 -validity 3650 -storepass PASSWORD
It will ask for a few identifying attributes of the certificate; it is possible to just press Enter every time. When
asked if the information is correct, type yes. At the last prompt (regarding the key password), press Enter, too.
(Option 2) If you already have a certificate, then conversion to a Java keystore is often still needed. The
certificate must be in DER (not PEM) format.
To specify the keystore for the JAR, copy its file to configRoot and modify application.properties:
server.ssl.key-store-type=PKCS12
server.ssl.key-store=${com.softneta.meddream.configRoot}/keystore.p12
server.ssl.key-store-password=PASSWORD
server.ssl.key-alias=tomcat
security.require-ssl=true
server.port=8443
server.port is here to minimize confusion: the current default port number, 8080, is normally used with HTTP,
not HTTPS.
When not using the well-known HTTPS port 443, you might need to always add https:// to MedDream URLs
from now on.
The Token Service can be configured by the same Spring Boot properties as above in its own
application.properties file.
In the simplest scenario, it is sufficient to reuse the same PKCS#12 file with server.ssl.key-store and server.
ssl.key-store-password. The example .properties file has those settings commented out.
This plugin adds custom text-only buttons to MedDream toolbar. They execute various URLs which can contain
metadata of an active image (like Study Instance UID) and are therefore suitable for additional integration with
third-party systems.
The custom buttons appear below the toolbar button “Plugins” that is hidden by default. Go to Settings and
search for “Plugins” in Viewer / Toolbar Settings, then choose at least “Show in desktop mode”.
To configure the plugin, modify the file medcadPlugins/links.json. By default, it contains a single entry that
implements a link to English version of the MedDream user manual:
[
{
"name": "Example: A link to User Manual",
"position": "VIEWER",
"openType": "ACTIVE_VIEWPORT_IFRAME",
"url": "../languages/en/help"
}
]
The top-level array can contain multiple entries instead of this single one. Elements of an entry:
The URL is constructed from url and searchParams by the frontend. The following placeholders that refer to
metadata from the active image can be used:
• STORAGE – identifies the current PACS plugin (its .id in application.properties)
• INSTANCE – (0008,0018) SOP Instance UID
• SERIES – (0020,000E) Series Instance UID
• STUDY – (0020,000D) Study Instance UID
• ACCESSION_NO – (0008,0050) Accession Number
• PATIENT_ID – (0010,0020) Patient ID
• EXAM_DATE – (0008,0020) Study Date
Button examples
• Opens http://demo.example.com in a new window:
{
"name": "External website demo",
"position": "ALL",
"openType": "NEW_WINDOW",
"url": "http://demo.example.com/"
}
{
"name": "Metadata in URL query",
"position": "VIEWER",
"openType": "SAME_WINDOW",
"url": "http://demo.example.com/",
"searchParams": {
"study": "STUDY",
"storage": "STORAGE",
"newParam": "otherValue"
}
}
• Opens a study in the active viewport, the UID is specified in the path and other parameters –
in the query (for example, http://demo.example.com/PacsOne/1.2.392.200036.9125.2.37100184241200.
64618798380.28802?image=1.2.826.0.1.3680043.6.6054.19688.20100603165016.704.123):
{
"name": "Metadata in URL query and path",
"position": "VIEWER",
"openType": "ACTIVE_VIEWPORT_IFRAME",
"url": "http://demo.example.com/{STORAGE}/{STUDY}",
"searchParams": {
"image": "IMAGE"
}
}
{
"name": "Run a 3rd party application on the client computer",
"position": "VIEWER",
"openType": "SAME_WINDOW",
"url": "applauncher:{STUDY}"
}
Custom URL handlers is a Windows feature that starts a registered application with the entire
URL on its command line. This example uses a generic protocol name “applauncher”. There
also are success stories for Linux (using gconftool-2) and OSX (using a specifically crafted
Application Bundle).
MedDream includes a couple of helper files for Windows:
– runAppFromBrowser/runAppFromBrowser.bat – a wrapper for 3rd-party applications. It
attempts to remove the “applauncher:” prefix from the command line and passes the
remainder to the application in form of studyuid=VALUE. You will need to adjust the path
to your application, and its command line;
– runAppFromBrowser/runAppFromBrowserReg.bat – registers the former file as a handler of
the applauncher protocol. Must be run in an elevated Command Prompt window. You will
need to adjust the path to runAppFromBrowser.bat and probably invent a better protocol
name instead of this “applauncher”.
It is possible to override some parameters when MedDream is opened via token, by adding the
pluginConfigurations element:
{
"items": [ ],
"pluginConfigurations": [{
"pluginName": "Metadata in URL query",
"parameters": [{
"name": "url",
"value": "http://example.com/viewer/"
},{
"name": "windowWidth",
"value": "300"
},{
"name": "windowHeight",
"value": "100"
},{
(continues on next page)
The parameters listed below can be left alone in most situations. The rarest of them aren’t included in
application.SAMPLE.properties for the sake of its simplicity.
1. MedDream root directory
com.softneta.meddream.configRoot = PATH_TO_MEDDREAM_DIRECTORY
All other directories are based on this value by default, therefore a correct specification means
less parameters are needed in application.properties.
If left unconfigured, the current directory of the JVM process is substituted automatically. The
substitution is based on the “user.dir” Java property, which in turn must be initialized by the JVM
and not via the -D option.
If the outcome is still incorrect, you can try to specify configRoot explicitly. It is expected in the
URI format; the “file://” prefix is mandatory and relative paths are not supported.
Examples:
com.softneta.meddream.configRoot = file:///opt/meddream
com.softneta.meddream.configRoot = file:///C:/MedDreamPACS/MedDream
com.softneta.meddream.configRoot = file:///C:/PROGRA~1/PacsOne/php/
meddream
2. Path to MedDream temporary files
com.softneta.meddream.tempDir = PATH_TO_MEDDREAM_TEMP_FILES
Allows to specify the path to a location where MedDream temporary files are stored; the default
“temp” below configRoot might not always be suitable.
Examples:
com.softneta.meddream.tempDir = ./temp (non-URI format might not work in all
cases)
com.softneta.meddream.tempDir = file:///mnt/mdtmp
com.softneta.meddream.tempDir = file:///E:/mdtmp
Note: Since 7.0 some cached files might need paths longer than 260 characters which are not
allowed under Windows. The only solution is to have com.softneta.meddream.tempDir as short
as possible.
server.servlet.session.timeout = 60
Some PACS plugins are slower and might take several minutes to load even the structure of a
large study (afterwards error icons are displayed instead of thumbnails). In these situations the
timeout should be increased.
Please remember that due to larger timeouts, client connections will persist longer in case of
inactivity or incorrectly closed MedDream window (using the “X” icon on the corner instead of
“Logoff”). With a license that limits the number of concurrent connections, this might exhaust the
free connections more often.
4. Session cookie name
server.servlet.session.cookie.name = MEDDREAMSESSID
Value in the example is a hidden default and won’t likely need correction.
For cases where the current value is used by HIS or different software on the same domain; in
these situations MedDream unpredictably loses its session.
5. IFRAME embedding permissions
This is the default and allows embedding MedDream only on the server that hosts it:
security.frameOptionsPolicy = SAMEORIGIN
#security.contentSecurityPolicy = frame-ancestors 'self'
security.frameOptionsPolicy = NONE
#security.contentSecurityPolicy =
security.frameOptionsPolicy = DENY
#security.contentSecurityPolicy = frame-ancestors 'none'
security.frameOptionsPolicy = ALLOW-FROM
security.frameOptionsWhitelist = 93.184.216.34,example.com
#security.contentSecurityPolicy = frame-ancestors 'self' \
# 93.184.216.34 example.com
server.servlet.session.cookie.secure = true
After configuring true, MedDream must be accessed over HTTPS or else the browser won’t
send session cookies back to the server after a successful login. Recommended in HTTPS-only
installations.
7. “SameSite” flag of the session cookie
server.servlet.session.cookie.sameSite = strict
The default value is the string “unset”, which means the flag is not added to the cookie. Other
possible values:
• none – no restrictions on the cookie, however the “Secure” flag is still mandatory. Not
supported by older browsers;
• lax and strict will further prevent embedding MedDream in an IFRAME, and might cause
problems with viewing DICOM PDFs.
Note: Since February 2020, Chrome changed the handling of cookies without this flag. Other
browsers will follow, too.
Now their default is “lax”; to get the older equivalent of “none”, you must specifically use sameSite
= none in MedDream settings.
With “lax”, MedDream should be hosted on a subdomain – for example, https://hospital.com will
be able to display an IFRAME containing https://viewer.hospital.com.
In application.SAMPLE.properties the “lax” version is commented out by default. You can
uncomment it if all your clients have compatible up-to-date browsers, as even support for “lax” is
not widely present.
security.xssProtectionDisabled = false
The header X-XSS-Protection is sent by default; true here will turn it off for troubleshooting etc.
9. Disable the X-Content-Type-Options header if needed
security.contentTypeOptionsDisable = false
The header X-Content-Type-Options is sent by default; true here will turn it off for
troubleshooting etc.
10. Address of the reverse proxy through which requests from Internet reach MedDream
security.meddreamProxyIp = 192.168.111.100
Needed to correctly extract remote IP addresses from the X-Forwarded-For header. This way
MedDream logs will contain true remote IPs instead of the proxy address (unless the proxy does
not provide X-Forwarded-For). Typically used in installations with both remote clients (they reach
MedDream via a proxy server) and local clients (direct connections from the LAN).
Empty by default. Must not be present if there is no proxy, or else MedDream will believe
spoofed values of X-Forwarded-For.
Since 8.3.1 hostnames beside IPs are supported, too.
11. Detect the change of remote IP address
security.detectRemoteIpChange = WARN
LOGOFF invalidates the session, WARN just logs a warning, OFF disables the feature (default).
Might also require settings server.tomcat.remote-ip-header = x-forwarded-for and
server.forward-headers-strategy = native.
12. Restrict client-side addresses that can open MedDream via HIS integration
security.authAllowedOrigins = 192.168.111.20,192.168.111.24
If not empty, IPs not in the list will be denied access to the /auth endpoint, which is a crucial part
of HIS integration.
13. Restrict client-side addresses that can use the Login window
security.meddreamLoginAllowHostIp = 192.168.111.0/24,dep.infra.acme.com
If not empty, IPs not in the list will get the same “403” page instead of the Login window, as in
case of meddream.loginEnabled=false.
CIDR-style subnets and hostnames are supported, too.
14. Limit the number of failed login attempts
com.softneta.meddream.maxAttemptsToConnect = 5
com.softneta.meddream.timeoutSeconds = 60
After maxAttemptsToConnect or more failures from the same IP address, any further attempts
will immediately fail (without validating the provided credentials) during next timeoutSeconds
seconds. The usual validation of credentials resumes after this time interval ends. The attempts
counter is reset by a successful login.
Default values are shown in the example. The limiting is disabled if at least one parameter is
zero. The setting security.meddreamProxyIp is important for correct IP addresses.
15. Path to writeable settings files (system.json / global.json / shortcuts.json / hangingProtocols.json /
columns.json)
com.softneta.settings.fileLocation = ${com.softneta.meddream.configRoot}/\
sys/settings
com.softneta.statistics.enabled = true
By default MedDream logs number of sessions and similar things to files statistics/YYYY-MM.stat
below configRoot.
When using the “pay per view” licensing model, these offline data provide proof for a certain
amount of monthly payment. In other cases statistics can help to find the optimal number of
concurrent connections or provide insights when troubleshooting performance problems.
17. Path to usage statistics files
com.softneta.statistics.fileLocation = ${com.softneta.meddream.configRoot}/\
statistics
The default value is shown above. In dockerized installations this option might be more
convenient than symlinks etc.
18. Local AE Title for saving annotations and screenshots
com.softneta.meddream.dcmsnd.bind = MEDDREAM
Created DICOM objects will be sent to the PACS over DICOM C-STORE. This Local AET
identifies MedDream as a sender. For testing purposes one might use any AET already accepted
by the PACS.
Not used in case of the “QR” plugin with storageApiEnabled=true because the plugin has a
separate parameter for Local AET.
19. Wait for annotation and screenshot object availability at the PACS
com.softneta.meddream.secToWaitAfterCreatedDICOMSend = 10
If this setting is nonzero, then a fresh PR/KO/RTSTRUCT/SC object must appear in study
structure not later than after this number of seconds. Default is zero and assumes that the
PACS will immediately import an object received via C-STORE.
20. Source of certain attributes in annotation and screenshot objects
com.softneta.meddream.newObjectsUseMetadataFromPacs = false
The default value is true and Patient ID is taken from the PACS by a dedicated request for
study metadata (normally the result isn’t cached and the request is executed during every save
operation). This might be beneficial if there is a chance that the PACS will change the Patient ID
without updating the DICOM files.
When changed to false, Patient ID is taken from attributes of the image being annotated (these
are normally cached). This is important for integrations where the Patient ID isn’t present in study
metadata at all.
21. Patient History scope for MultiPACS configurations
com.softneta.meddream.searchPatientHistoryInAllStorages = true
The default value is false: the PACS from where the study was opened, also provides the patient
history for this study. In contrast, true forces searching for related studies in all PACSes available
to the current user.
22. Credentials for management endpoints like /manage, /h2-console, etc.
authentication.manager.username = LOGIN_NAME
authentication.manager.password = LOGIN_PASSWORD
Use a strong password, and do not leave it configured longer than necessary. (An empty
username or password makes the login impossible.)
Note: Both values can also be file names, or paths to files, from where the final content will
be loaded. A successful load operation is not indicated in the logs. File contents are used as is,
without removing empty lines, whitespace or newline characters (please make sure that there is
no line ending in the file).
Due to this “hidden” functionality, a quite rare bug is possible: when you have a too simple
password that matches the name of an existing file, then content of that file is used instead,
without any warning. Strong passwords will prevent that. With usernames the chance is
obviously higher.
management.endpoints.enabled-by-default = true
management.endpoints.web.exposure.include = *
This is diagnostic functionality for qualified personnel. The endpoint can be used to examine
MedDream logs etc. over HTTP, therefore it presents a security risk.
Do not leave it configured longer than necessary, and use a strong password in
authentication.manager.password.
By default .enabled-by-default is false and yields an empty directory anonymously; .include is
just health.
It is also possible to trim down the amount of exposed data as it might contain information sought
by hackers. You should enable only individual subsets relevant to your case. The example below
exposes only /manage/env and /manage/health:
management.endpoint.env.enabled = true
management.endpoint.health.enabled = true
management.endpoints.web.exposure.include = env,health
By default /manage is available on the same port and address(es) like other parts of MedDream.
It is strongly recommended to at least use a different port, or even bind to 127.0.0.1 to prevent
access from other machines:
management.server.port = 8081
management.server.address = 127.0.0.1
spring.h2.console.enabled = true
spring.h2.console.settings.web-allow-others = true
logging.level.ROOT = ERROR
logging.level.com.softneta = INFO
logging.level.com.softneta.meddream.dicomStoreServer = DEBUG
logging.file.name = meddream
#logging.file.name = /opt/md/log/meddream
Commenting this line out will disable logging to file. The console, if visible, will still receive the
messages.
Do not include the extension; it is added automatically together with additional suffixes.
A path can be included, too. All directories must exist, the last one must be writeable by the user
under which the JRE process is running. A related Spring Boot setting, logging.file.path, only
allows to change the path while keeping default file names (logging doesn’t work if you add both
settings).
27. Limit size of old log files
logging.logback.rollingpolicy.max-file-size = 10MB
The log file is automatically rotated (renamed to *.log.1, *.log.2, . . . ) when its size reaches this
value.
Before 8.1.0, logging.file.max-size was suggested instead, however it didn’t work.
28. Limit number of old log files
logging.logback.rollingpolicy.max-history = 10
During log rotation, the oldest ones are removed unless this parameter is set to 0.
Before 8.1.0, logging.file.max-history was suggested instead, however it didn’t work.
29. Base directory for caching thumbnails, pixel data, DICOM attributes and study structure objects
com.softneta.preparation.cacheDir = ./temp/cache
com.softneta.video.convertedDir = ./temp/converted-videos
{INPUT} and {OUTPUT} are automatically replaced with corresponding file names. There is no
support for options with embedded spaces, and quoting will not help; the space character
always separates adjacent options.
The default value is shown in the example. It utilizes a software H.264 encoder available in most
builds of FFmpeg.
If you have a hardware encoder, it might be possible to speed up the conversion
without noticeable loss of quality. For an Nvidia video adapter under Windows, one
can try the command line -hwaccel cuda -i {INPUT} -y -vcodec h264_nvenc -preset slow
-movflags faststart {OUTPUT} after installing recent drivers (the version in Windows Update
might still be too old). Experiments under Linux will need a recent FFmpeg build, at least
configure’d with --enable-nvenc. Do not forget to examine the files *.out under convertedDir
if the conversion is failing.
The thumbnail creation command line is hardcoded in a third-party library (not configurable).
32. Directory to store temporary anonymized images before uploading to DICOM Library
com.softneta.dicom.library.upload.tempDir = ./temp/upload-to-dicom-library
com.softneta.export.tempDir = ${com.softneta.meddream.tempDir}
com.softneta.export.tmpCleanAfterMilliSec = 86400000
com.softneta.export.fileAliveTimeInMillis = 10800000
com.softneta.export.additionalSoftwarePath=
(continues on next page)
com.softneta.dicom.library.upload.anonymizeLevel = false
com.softneta.meddream.patientStudyCountEnabled = false
This is not needed under normal circumstances (value should remain true).
36. Open a custom viewer from Search window
com.softneta.meddream.alternativeViewerUrl = http://SERVER/viewer?study={study}
If not empty, the Search window will open this URL instead of the Viewer window.
Can contain placeholders “{study}” and “{storage}” that will be replaced with Study Instance UID
and storage ID. If “{study}” is missing, then a hardcoded query “?studyUid=<Study Instance
UID>&storageId=<storage ID>” is appended. The other one, “{storage}”, is optional.
37. Bind address of the HTTP server
server.address = 192.168.200.100
This parameter can be used to expose MedDream on a single IP address that belongs to the
machine. The default value is 0.0.0.0, meaning “all IP addresses”.
38. HTTP context path
server.servlet.context-path = /meddream
By default the MedDream backend is available at /. Some reverse proxying scenarios might
benefit from different values.
39. Enable/disable compression of HTTP responses
server.compression.enabled = true
server.compression.mime-types = application/octet-stream
If the first parameter is set to true (by default it’s false), then the second one lists comma-
separated MIME types to which the compression will be applied.
40. Maximum size of HTTP headers
server.max-http-header-size = 24576
com.softneta.meddream.http.brandingCacheMaxAgeSec = 0
The /branding resource will expire in proxy/browser caches after this many seconds. Zero
(default) turns the caching off, that is, the browser will always perform the request anew. Before
8.0.0, the value was hardcoded as 3600.
42. Rename robots.txt
com.softneta.settings.robotsFileName = robots.txt
MedDream is shipped with an example file sys/settings/robots.txt. If you are experimenting with
multiple files, it might be more convenient to point to a different one instead of rewriting contents
of the same file.
43. Adjust what color palettes are offered, and in what order
#com.softneta.meddream.enabledColorPalettes = HOT_IRON,PET,HOT_METAL_BLUE,\
# PET_20_STEP,SPRING,SUMMER,FALL,WINTER
com.softneta.meddream.enabledColorPalettes = HOT_IRON,PET,HOT_METAL_BLUE,\
PET_20_STEP,RAINBOW
Affects both Fusion functionality and the Color Palette Selection widget.
The default value (effective when application.properties doesn’t contain the setting, or it’s
commented out) is shown in the commented-out example. Those are the standard palettes.
The second version is offered in the configuration samples, and contains a custom palette
“RAINBOW” instead of a few standard ones.
Custom palettes are stored as files sys/clut/*.json, file name must be listed in the setting
exactly (case sensitive). The accompanying icon is expected as a file sys/clut/icons/*.png
and is declared in form of a relative URL palette/*.png via the “thumbnailUrl” parameter in the
JSON file.
44. “Share via DICOM Library”: upload chunk size in bytes
com.softneta.dicom.library.upload.partSize = 100000
The default is 1 MB. If the Internet connection to DICOM Library is slow, then smaller values
might yield faster recovery from connection drops.
45. “Share via DICOM Library”: number of retries and related pause
com.softneta.dicom.library.upload.repeatTimes = 5
com.softneta.dicom.library.upload.repeatAfterSeconds = 5
If the upload process fails, then the related job pauses for repeatAfterSeconds seconds and
retries up to repeatTimes times.
46. “Share via DICOM Library”: thread pool management
com.softneta.dicom.library.upload.job.corePoolSize = 10
com.softneta.dicom.library.upload.job.maxPoolSize = 100
com.softneta.dicom.library.upload.job.keepIdleForSeconds = 30
See https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/
ThreadPoolExecutor.html. Initially, corePoolSize threads are ready for work; up to maxPoolSize
threads can be created on demand and they will be terminated after keepIdleForSeconds
seconds of inactivity.
47. Local Storage SCP: AE Title
com.softneta.dicomStoreService.localAETitle = MEDDREAM
PACSes need to know this value, the corresponding IP and port for sending images to
MedDream. “MEDDREAM” is the default.
localAETitle also accepts multiple values separated by commas. Even more, an empty
parameter will result in any Called AE Title being accepted (some PACSes, too, don’t care about
the Called AE Title).
48. Local Storage SCP: TCP port
com.softneta.dicomStoreService.port = 11116
com.softneta.dicomStoreService.address = 192.168.111.70
By default the SCP binds to 127.0.0.1. This parameter can specify a single address, including
“0.0.0.0” which means all available addresses (that was the default before MedDream 8.0.0).
A symbolic name will automatically resolve to a numeric address, but this isn’t recommended
unless a single address is known to the resolver.
50. Local Storage SCP: base directory for received DICOM files
com.softneta.dicomStoreService.saveDirectory = ${com.softneta.meddream.tempDir}/
˓→STORE
If left empty, the SCP will not start. The default value is “STORE” under tempDir.
For better compatibility with the temporary files cleaner, empty value is recommended here
instead of commenting the entire setting out.
Under this directory the SCP creates received files: CALLING_AET/ STUDY_INSTANCE_UID
/SERIES_INSTANCE_UID/ SOP_INSTANCE_UID.dcm. Avoid long saveDirectory under
Windows, because together with UID values from the files the path might become longer than
supported by some third-party applications.
51. Local Storage SCP: accepted Calling AE Titles
com.softneta.dicomStoreService.acceptAETitles = DCMSND,SENDTOPACS
com.softneta.dicom-store-service.allowedIps = 192.168.111.87,192.168.111.88,\
192.168.111.91
If not empty, then DICOM file uploads and C-ECHO connections will be allowed only from the
listed IP addresses. Clients from wrong addresses will see an immediate socket closure (a
connection reset).
Totally hiding the listener from some clients, as if nobody listens at the port, is possible only at a
lower network layer and requires a firewall.
53. Local Storage SCP: number of simultaneous connections
com.softneta.dicomStoreService.multiThreadCount = 5
com.softneta.dicomStoreService.preferSingleComprSyntaxInCtx = true
Some DICOM senders are proposing presentation contexts with multiple transfer syntaxes. The
Standard allows to accept only one syntax. By default, the first one is accepted. As it’s often
Implicit VR LE, the sender becomes obliged to uncompress the object, which wastes time and
resources.
If true is configured here, MedDream verifies whether the syntaxes are uncompressed except a
single one, and accepts only that syntax. (Looks like it’s a popular scenario with Sectra software.)
If, however, the list contains more than one compressed syntax, then the first from the list is
accepted again.
MedDream can’t possibly know which syntax is the original one and therefore most efficient for
sending. The sender can avoid this ambiguity by sending the original syntax first, or by packing
every syntax:class pair in a separate context.
55. Local Storage SCP: create preparation jobs
com.softneta.dicomStoreService.prepareReceivedFile = true
true: after receiving an IAN message, or a file over C-STORE, a preparation job will be created.
56. Local Storage SCP: create preparation jobs for certain Called AE Title values only
com.softneta.dicomStoreService.prepareForTheseLocalTitles = MEDDREAM1,MEDDREAM2
When prepareReceivedFile is true, this parameter can restrict values of Called AE Title for
which preparation jobs are created. Applies to C-STORE only, not IAN. No restrictions if empty
(default).
Unless localAETitle is empty (by default it isn’t), the allowed values must be from localAETitle.
57. Default value of (0008,0005) Specific Character Set when this attribute is missing in the DICOM file
com.softneta.dicomParser.defaultCharset =
com.softneta.dicomParser.defaultCharsetOverride = false
true will ignore any declarations in DICOM files. This might be adequate in a (small) clinic where
all modalities specify wrong Specific Character Set.
59. Disable rendering of old-fashioned overlays
com.softneta.dicomParser.builtInOverlayEnabled = false
MedDream 8.2 began to render overlays that are stored in unused bits of Pixel Data. false here
will disable that.
Overlays specified via the (60xx,3000) attribute are supported since initial versions, and can not
be disabled.
60. Do not use the built-in DICOM Dictionary
com.softneta.dicomParser.useJdtLookupDDict = false
Since 8.3 the declared Value Representation of every DICOM attribute is ignored and is taken
from a built-in dictionary instead (this setting is true by default).
Change to false for previous behavior. Some files that violate the standard might need different
values of this setting. Hopefully a particular installation doesn’t have both kinds of files.
61. Allow parsing of listed private tags
By default private tags are ignored. Consequently, standard tags in private sequences are
inaccessible, too.
com.softneta.dicomParser.additionalPrivateTags = 00430010,2001105F/2005107B
#com.softneta.dicomParser.additionalPrivateTags[0].tagTree=2001105F/2005107B
#com.softneta.dicomParser.additionalPrivateTags[0].inEveryLevel=true
Simple syntax is tag numbers (8 hexadecimal characters) separated by commas. In this syntax
tags are taken only from the root level. If the number is prefixed by slash-separated container
number(s), like SEQ1/SEQ2/TAG1 instead of just TAG1, then the tag is taken from specified
sequence(s) starting at root level.
Extended syntax, which is commented out in the example, allows to specify a tag number or
path, and enable searching for it everywhere – not only from the root level.
Tags needed by certain functionalities, namely 00211106, 00291010 and 001910D7 (all with
inEveryLevel=true), are added to this parameter automatically.
62. MedCAD: path to backend plugins directory
com.softneta.meddream.medcad.pluginsDir = ./medcadPlugins
com.softneta.meddream.medcad.frontendPluginsDir = ./md5/plugins
The value in this example is the default, and currently it’s hardcoded in the frontend.
64. HIS integration: JWT security layer
authentication.his.jwtServiceAddress = http://192.168.111.30:90/jwt/
authentication.his.jwtServerKey = ATDwsT...DFHTQ==
authentication.his.jwtMedDreamKey = DjSWFt...psVzg==
authentication.his.responseDecryptPassword = g9RxMR...an67Z4=
authentication.his.responseDecryptSalt = /9kzgA...pYdnw==
security.cookieSecureFlag = false
A custom token validator can use JSON Web Tokens instead of the “token” URL parameter. (Not
supported by the validator shipped with MedDream.)
This mode is enabled by adding a header Authorization: Bearer JWT_STRING to the initial
(at least) request to MedDream. In this case jwtServiceAddress must be configured because
MedDream will send the JWT in a header of a POST request to this URL and expect the same
JSON object as from the usual HIS integration. The service can use claims in the token to
identify what needs to be returned.
The request to jwtServiceAddress will contain the original JWT – or, if jwtMedDreamKey and
jwtServerKey are configured, then MedDream verifies original signature with jwtServerKey and
re-signs the token with jwtMedDreamKey (both operations support only HMAC-SHA of length
256, 384 and 512).
If responseDecryptPassword and responseDecryptSalt are configured, then MedDream will
decrypt the response (AES in GCM mode, no padding) before parsing it as JSON.
The password, salt and keys must be specified in Base64 format.
If cookieSecureFlag is true, the “md-jwt” cookie is sent over HTTPS only.
65. LiveShare
#liveshare.guestRoles=
#liveshare.linkStrategy=SIMPLE_HIS
#liveshare.liveShareTokenValiditySeconds=3600
#liveshare.tokensGeneratorService=http://192.168.111.30:111/v3/generate
#liveshare.tokensInvalidationService=http://192.168.111.30:111/v3/invalidate
com.softneta.preparation.prepareStudyInstancesThreadCount = 5
(continues on next page)
#com.softneta.preparation.expandEnhancedDicomThreadCount = 8
com.softneta.preparation.sopClassesForConversionToVideo = 1.2.840.10008.5.1.4.1.
˓→1.3.1
com.softneta.preparation.sopClassesForMoveToNewSeries =
#com.softneta.preparation.sopClassesForScoutImageMoveToNewSeries = 1.2.840.
˓→10008.5.1.4.1.1.2
com.softneta.preparation.skipExpandedFrameThumbnailPreparation = false
com.softneta.preparation.skipStructurePreparation = false
com.softneta.preparation.skipInvalidFrames = false
com.softneta.preparation.updateTagsFromPixelContent = false
com.softneta.preparation.useSessionCache = false
com.softneta.preparation.removeHtmlTagsFromSr = false
See https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/
ThreadPoolExecutor.html. Initially, coreThreadCount threads are ready for work and up to
maxThreadCount threads can be created on demand. The same is valid for other similar sets of
parameters, prepareStudyInstances* and downloadDicom*.
Threads are terminated after threadTimeoutSeconds even if busy. You might need more time if
some files are very large.
For every multiframe file, up to multiFrameThreadCount threads will be created for processing
frames of the same file in parallel.
MedDream 7.7.0+ exhibits a different thumbnail display and an optimized study loading.
By default only a single “summary” thumbnail is displayed for series of modalities listed in
thumbnailCreationModalities and, due to thumbnailCreation = all, remaining thumbnails are still
created in advance. thumbnailCreation = first might cause the study to be displayed quicker, at
a cost of slower opening of a series after clicking on its summary thumbnail. Note, however,
that first applies only to series with modalities in thumbnailCreationModalities; for other kinds
of series, all thumbnails are always displayed and created. thumbnailCreationSopClasses is an
alternative to thumbnailCreationModalities, based on a different DICOM Attribute.
The downloadDicom* parameter set is used in the “Preload series” and “Preload study” scenarios
to make sure the DICOM files are downloaded and cached before processing their contents. It
might make a big difference with non-direct integrations (QR, Orthanc, Dicomweb, etc) that have
the caching enabled.
cachePreparationFiles controls an in-memory index of cached files. In 7.8.0+ it is false by
default, this saves a significant amount of memory; however outdated files are only removed by
temporary files cleaner (see below). The legacy value, false, might improve performance and
usually results in automatic removal of outdated files – even without the temporary files cleaner.
compressPixelsBeforeSave turns on compression during caching (possible values are gzip
or true, lz4, false); batchImageRequests is then ignored and remains false. This
might be better than server.compression.enabled as the latter is performed on every request.
Both options have little sense if the network connection is fast enough. After changing
compressPixelsBeforeSave, you must clear all cached data (see com.softneta.preparation.
cacheDir).
cacheTimeToIdleSeconds is the main means to indirectly control the cache size. The preparation
cache removes outdated files according to it. The cache will not work properly if files are removed
by external means, like manually or by the preparation-related entry in configuration of temporary
files cleaner. The latter must therefore be used only as a last resort (to clean files that became
orphaned due to an application crash, etc), and its time limit must be significantly higher than
cacheTimeToIdleSeconds – at least a few times higher.
If trackDicomModifications is true, MedDream makes sure that a cached file is created anew
if the original DICOM file has a newer Last Modified timestamp. This lowers the risk of displaying
outdated patient information, however if MedDream and PACS are on different machines, then
their system clocks must be synchronized for better protection and to avoid repeated re-caching.
com.softneta.preparation.additionalMetadataTags = 00080070,00191018,2001105F/
˓→2005107B
00540220 SQ
FFE000E0
00281050 DS [1]
(continues on next page)
com.softneta.video.preparationTimeLimitSec = 60
In order to start FFmpeg for video conversion, MedDream requires some data from related
preparation tasks and waits up to this time for them to finish. A heavily loaded server might
require more time.
In case of a corresponding timeout, the logged error message suggests to increase this value.
There is little sense to do it in advance.
69. Temporary files cleaner
Files are removed by their modification date.
You can configure multiple locations with a distinct file name pattern and maximum age. The
setting matchAnyDepth=false disallows searching for a match in every subdirectory and beyond,
thus helps to avoid needless scanning of underlying large directory trees. The age also applies
to directories; if a directory name at some level matches the pattern, and age is suitable, then the
entire directory subtree is removed even if some deeper contents are newer. There is, however,
an exception for .pattern equal to *: first the files of suitable age are removed, then their parent
directories if they became empty.
The cleaner executes every cleanRateMilliSec or according to expression in the cron setting.
Since 8.2 execution can also start outside this schedule if freeSpaceThresholdPct is configured
(larger than zero) and, after verification every monitoringFrequencyMilliSec (larger than zero),
the amount of free space is found lower; it will stop as soon as there is enough free space.
cleanRateMilliSec is relative to the application start. The value of 86400000 (one day) means
that if the application was restarted during some peak load at noon, the next cleaning will also
start during peak load next day.
If a more flexible schedule is needed, then set cleanRateMilliSec to -1 and specify the cron
parameter instead. The string must contain 6 entries: second, minute, hour, day, month,
weekday. Examples:
• 0 0 * * * *: beginning of every hour.
• 0 0 8-10 * * *: 08:00, 09:00, 10:00.
• 0 0 6,19 * * *: 06:00 and 19:00.
• 0 0/30 8-10 * * *: 08:00, 08:30, 09:00, 09:30, 10:00 and 10:30 every day.
• 0 0 9-17 * * MON-FRI: from 09:00 to 17:00, once per hour, weekdays.
• 0 0 0 25 12 ?: on Christmas Day at midnight.
Since 8.2 every cleanable location can have its own values for cleanRateMilliSec (or cron)
and freeSpaceThresholdPct. For the latter, however, you need separate volumes/disks, as
otherwise file systems report the same amount of free space.
corePoolSize and maxPoolSize help to utilize the CPU better. For example, 8 threads on a
recent computer makes the operation approximately three times faster. One thread is used
by default, which corresponds to pre-8.2 behavior. The default thread priority configured by
poolPriority is 1 (the lowest possible), you can increase it to 5 (same as other threads in
MedDream).
The default configuration, which is duplicated below, lists known locations with possible leftover
temporary files.
#com.softneta.temp-cleaner.disableCleaner = true
com.softneta.temp-cleaner.cleanRateMilliSec = 1800000
#com.softneta.temp-cleaner.cron = 0 30 0 * * *
#com.softneta.temp-cleaner.monitoringFrequencyMilliSec = 0
#com.softneta.temp-cleaner.freeSpaceThresholdPct = -1
#com.softneta.temp-cleaner.corePoolSize = 1
#com.softneta.temp-cleaner.maxPoolSize = 1
#com.softneta.temp-cleaner.poolPriority = 1
com.softneta.temp-cleaner.tempItems[0].directory = ${com.softneta.\
preparation.cacheDir}
com.softneta.temp-cleaner.tempItems[0].pattern = *
com.softneta.temp-cleaner.tempItems[0].olderThanSec = 604800
com.softneta.temp-cleaner.tempItems[1].directory = ${com.softneta.\
meddream.tempDir}
com.softneta.temp-cleaner.tempItems[1].pattern = *_archive
com.softneta.temp-cleaner.tempItems[1].olderThanSec = 7200
com.softneta.temp-cleaner.tempItems[1].matchAnyDepth = false
com.softneta.temp-cleaner.tempItems[2].directory = ${com.softneta.\
meddream.tempDir}
com.softneta.temp-cleaner.tempItems[2].pattern = *_export
com.softneta.temp-cleaner.tempItems[2].olderThanSec = 21600
com.softneta.temp-cleaner.tempItems[2].matchAnyDepth = false
com.softneta.temp-cleaner.tempItems[3].directory = ${com.softneta.\
meddream.tempDir}
com.softneta.temp-cleaner.tempItems[3].pattern = forward_*.dcm
com.softneta.temp-cleaner.tempItems[3].olderThanSec = 7200
com.softneta.temp-cleaner.tempItems[3].matchAnyDepth = false
com.softneta.temp-cleaner.tempItems[4].directory = ${com.softneta.\
meddream.tempDir}/3d
com.softneta.temp-cleaner.tempItems[4].pattern = *
com.softneta.temp-cleaner.tempItems[4].olderThanSec = 7200
com.softneta.temp-cleaner.tempItems[5].directory = ${com.softneta.\
video.convertedDir}
com.softneta.temp-cleaner.tempItems[5].pattern = *
com.softneta.temp-cleaner.tempItems[5].olderThanSec = 3600
com.softneta.temp-cleaner.tempItems[6].directory = ${com.softneta.\
dicom.library.upload.tempDir}
com.softneta.temp-cleaner.tempItems[6].pattern = *
com.softneta.temp-cleaner.tempItems[6].olderThanSec = 86400
#com.softneta.temp-cleaner.tempItems[7].directory = ${com.softneta.
˓→dicomStoreService.saveDirectory}
#com.softneta.temp-cleaner.tempItems[7].pattern = *
#com.softneta.temp-cleaner.tempItems[7].olderThanSec = 86400
#com.softneta.temp-cleaner.tempItems[7].freeSpaceThresholdPct = -1
#com.softneta.temp-cleaner.tempItems[7].cleanRateMilliSec = 0
#com.softneta.temp-cleaner.tempItems[7].cron =
Take caution with the last entry (related to saveDirectory). If you uncomment it and the related
com.softneta.dicomStoreService.saveDirectory setting is commented out, then the cleaner
receives a literal string ${com.softneta... and might misbehave. When not using the local
DICOM receiver, you should either comment out (or remove) this entire cleaner entry, or set
saveDirectory to an empty string (it is ignored both by receiver and cleaner).
The entry that cleans com.softneta.preparation.cacheDir should have a time limit a few
times higher than com.softneta.preparation.cacheTimeToIdleSeconds, or else intermittent cache
failures will result.
If you use some PACS plugins that download DICOM files instead of directly accessing them on
PACS file system (like “Orthanc” or “Dicomweb”), then their cache directories need to be added
here, too.
70. Old jobs cleaner
com.softneta.preparation.scheduleJobRemovalInSeconds = 0
com.softneta.preparation.job-cleaner.cron = 0 45 0 * * *
Completed jobs from Preparation and Share functionality are not removed immediately. The
legacy behavior corresponds to scheduleJobRemovalInSeconds = 30, cron = - (a job is
removed 30 seconds after completion) and is suspected to cause problems when jobs are
created quite often. Starting from 7.7, MedDream will attempt to remove the jobs at a certain
time (00:45 nightly by default) and only those older than one hour.
71. Google Analytics ID (when using GA to track user activity)
com.softneta.meddream.googleAnalyticsId = UA-000000-2
The GA client code is already included into MedDream, you only need to specify your website
ID.
72. How often the in-memory index of the cache is cleaned
com.softneta.ehcache.cacheCleanRate = 1800000
com.softneta.preparation.persistCache = true
com.softneta.ehcache.cachePersistRate = 3600000
com.softneta.cache.studyStructureSec = 300
com.softneta.cache.pgwStudyResponseSec = 0
The in-memory cache index can be made partially persistent. If persistCache is true,
MedDream dumps the cache index to disk every cachePersistRate milliseconds, and loads
it during startup. This way the cache index is not completely lost when restarting the service,
however some orphaned files will remain. This, of course, costs CPU and I/O operations, and
slows down the startup.
Experiments will be needed to find out an optimal cachePersistRate that doesn’t waste too much
resources and still preserves enough changes in case of unplanned application restart.
The preparation cache index is preserved in a file “cache.keys” in tempDir. Other two kinds of
caches that can be preserved are: study structure cache (files “struct” in some subdirectories of
cacheDir, created if studyStructureSec is larger than 24h) and HIS integration response cache
(files “search” in some subdirectories of cacheDir, created if pgwStudyResponseSec is larger
than 24h). The main purpose of studyStructureSec and pgwStudyResponseSec is for how many
seconds entries can remain in the corresponding cache.
The Temporary files cleaner above is still needed as a last-resort means. Running every few
days might be sufficient.
Note: studyStructureSec is 300 by default since 8.0. This means that the study structure will
not be queried from the PACS more often. At least 5 minutes must pass until any known changes
at the PACS, like newly added series or removed images, become visible in MedDream. The
“Clear cache” functionality can remove the cached structure earlier.
com.softneta.meddream.dcmsnd.forwardingMethod = native
#com.softneta.meddream.dcmsnd.forwardingMethod = plugin
#com.softneta.meddream.dcmsnd.forwardingMethod = cmove
com.softneta.meddream.dcmsnd.dicomParseThreadCount = 5
com.softneta.meddream.dcmsnd.dicomSendThreadCount = 1
to this number of studies in parallel, therefore a larger number might improve the experience of
Forward for concurrent users.
76. SOCKS5 proxy address for the Forward function
DICOM receivers might validate the source IP address of an incoming session. Suppose the
devices already know the address of the PACS machine; a new address (of MedDream machine)
cannot be added to them due to some reason, while MedDream must run on a different machine
than the PACS. The solution is to set up a SOCKS5 proxy and run its server part on the PACS
machine. MedDream, in turn, must know about the client part of the proxy:
com.softneta.meddream.dcmsnd.forwardProxyHost = 192.168.111.222
com.softneta.meddream.dcmsnd.forwardProxyPort = 4567
If both parameters are specified, then the Forward function and upload of annotations (PR, KO,
segmentations, screenshots) will pass all DICOM communication to the specified proxy so that
the traffic comes out from a different IP address. For MedDream there is no significant difference
where the client part is running: on the PACS machine, on the MedDream machine, or on a
totally different machine.
Setting up such a proxy is beyond the scope of this document. OpenSSH is suitable both for
Linux and Windows; Shadowsocks is a good alternative.
77. Use the original AE Title when sending annotations
When sending annotations to the PACS, the C-STORE
client uses its own AE Title from non-empty value of
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].storeScuAet, then
from com.softneta.meddream.dcmsnd.bind.
However, if this parameter is true, the first value attempted is the original AE Title already
associated with the study.
com.softneta.meddream.dcmsnd.annotationsFromOrigAet = true
NOTE: this was tested only with PacsOne plugin. Some plugins will not return the study’s AE
Title at all, while some others might return multiple values from different series and this is not
handled properly at the moment.
78. Require user identity in ATNA messages (EXPERIMENTAL)
com.softneta.audit.requireUserIdentity = true
Historically ATNA messages from MedDream have a fake user identity (”login@domain” etc).
Some scenarios, mainly those based on token integration (but not on Login window), carry a
true identity. Set this parameter to true in order to crash (a stack trace will be visible in the
application log) when attempting to send a fake identity via ATNA. On the one hand, messages
like these won’t reach the ARR at all; on the other hand, this will help to identify scenarios that
still need an update, provided that you are monitoring the logs.
79. Disable sorting of toolbar buttons after a version upgrade
com.softneta.meddream.toolbarButtonsOrderingEnabled = false
By default toolbar buttons are reordered after the upgrade (when the new JAR reads the files
*global.json saved by an earlier version). This way newly added buttons don’t go unnoticed.
If false is specified here, then no reordering is done and new buttons are added at the end.
Useful for some installations with a customized list of buttons where it would be too time-
consuming to recreate the custom order manually.
80. Calculation of “main modality” for the study structure (EXPERIMENTAL)
Some modality-related decisions become too complicated with studies having multiple modality
values (like “CT, KO, PR, SR”), compared to single-modality studies (like “DX”). As of 8.3, a
single equivalent value is already calculated, however it is still being integrated into the workflow.
com.softneta.study.modalityWeight.CT = 1200
com.softneta.study.modalityWeight.PT = 100
The number of series with a particular modality is multiplied by configurable weight and the
modality with the highest score “wins”. There is an extensive list of default weights, with 1000 for
many popular values like RG, then 300 for PT and 100 for SR.
In this example, a typical study with both CT and PT series is still considered as “CT” because
CT has a higher weight assigned. If, however, there are more than 12 PT series for 1 CT series,
the result will be “PT”.
81. List of modalities to move series to the end of the study structure
com.softneta.study.lowerPrioritySeriesModalities = OT,SR
Warning: MedDream sessions are incompatible with H2 Console sessions. Use the incognito mode or
another browser if MedDream must be used at the same time.
Otherwise, you will need to log out fully every time. The H2 Console has a “Disconnect” button. MedDream
toolbar has a “Log Off” button, which is renamed to “Close” in HIS integration mode (and logs off, even if the
window fails to close afterwards).
spring.h2.console.enabled = true
spring.h2.console.settings.web-allow-others = true
authentication.manager.username = ADD_USER_NAME_HERE
authentication.manager.password = ADD_STRONG_PASSWORD_HERE
2. Open SERVER_IP:SERVER_PORT/h2-console in the browser. The browser will request HTTP credentials
configured above, then display Console’s own graphical login form.
3. In the Console login form, make sure the JDBC URL form field contains
jdbc:h2:file:MEDDREAM_ROOT_DIR/sys/database/DB_NAME (with real path instead of
MEDDREAM_ROOT_DIR, and real database name instead of DB_NAME).
Example: jdbc:h2:file:C:/PROGRA~1/PacsOne/php/meddream/sys/database/reportdb.
4. User Name is normally “sa”, however the “authdb” database requires an empty value. Password must
always be empty.
5. Press the Connect button.
6. You should now see some table names at the left, unless an empty database is expected.
Warning: Leaving H2 Console enabled for a long time is a security risk. Disable it as soon as the work is
done, with spring.h2.console.enabled = false.
The safest way is to always use spring.h2.console.settings.web-allow-others = false: the Console
will then open on localhost only. This is OK for Windows machines, as they are often managed via Remote
Desktop or similar graphics-capable means, and a browser can be run on the server itself. For Linux
machines accessed via SSH, we advise to tunnel the corresponding port (likely localhost:80) to some other
port on operator’s machine, and open a browser there.
By default MedDream uses H2 for all built-in databases. The reason is simplicity: they can be created
automatically due to nature of this DBMS.
MySQL or MariaDB is supported as an alternative. It is advised for installations with high load (for example,
large hospitals with preparation enabled). Switching is easier if done shortly after installation, and involves the
following steps:
1. Create two new databases in MySQL. We suggest names mdquartz and mdbatch although any names will
be OK. It is essential to have dedicated databases instead of reusing some existing one.
2. Create a dedicated user that has access only to these databases and only from a specific machine. Avoid
using the ``root`` user. Example:
Substitute a new password for PASS. Do not reuse existing ones as this password will be visible
in the configuration file.
3. Add to application.properties:
spring.flyway.locations = classpath:/batch/db/mysql
datasource.quartz.url = jdbc:mysql://SERVER:PORT/mdquartz?user=USER\
&password=PASS
datasource.quartz.driverClassName = com.mysql.cj.jdbc.Driver
datasource.batch.url = jdbc:mysql://SERVER:PORT/mdbatch?user=USER\
&password=PASS
datasource.batch.driverClassName = com.mysql.cj.jdbc.Driver
SERVER, PORT, USER and PASS must be changed to real values. If you gave different names
instead of mdquartz and mdbatch, then they must be changed as well.
4. Start the MedDream service.
• In case of fatal errors, like unrecognized password, the service will fail to start. Check whether it’s still
running after a couple of minutes.
• Look for any new ERROR messages or stack traces in the log.
• Verify that a few tables, including flyway_schema_history, have been created in each database.
• Try using functionality that involves background jobs, like in-advance preparation (triggered either by
IAN messages or forwarded files) or Share via DICOM Library.
At the moment Softneta doesn’t provide instructions on how to transfer contents of these databases, as in most
cases they are of little value and can be recreated at virtually no cost.
This hardening has a cost, however: just before every upgrade of MedDream you will need to restore ALL
PRIVILEGES for a short time. If you forget that, you’ll get an error like “ALTER command denied to user”, and
the flyway_version_history table will remain in a broken state: retries will result in error “Schema . . . contains
a failed migration”. The latter can usually be fixed by removing the newest record from the table (look at the
“installed_on” timestamp); however a safer way is to restore the entire database from a backup.
Sometimes one needs a non-default context path, like http://server.tld/meddream/ instead of just http://
server.tld/ (for example, to isolate multiple installations of MedDream).
A proven solution involves accessing the backend via a proxy that changes every “/meddream” to “/meddream/”.
For Apache, the following mod_rewrite directive solves the problem:
If a reverse proxy is used, it might interfere with websockets. Currently MedDream depends on the latter for
configurations with features.liveShare=true or openTabsTrackingMethod=SOCKETS (both can be enabled in
system.json).
A most common failure is due to the Origin header added by proxies, that results in a message “Handshake
request rejected, Origin header value https://127.0.0.1 not allowed” in MedDream logs. To correct that, you can
add the following to the proxy configuration:
• Apache: RequestHeader unset Origin (requires mod_header);
• Nginx: proxy_set_header Origin "";
Note: MedDream 8.0.0+ enables most options by default; sender’s AE Title still needs to be specified manually.
The DICOM Listener (local Store SCP) can run in parallel to any kind of PACS integration.
Non-direct integration plugins like Orthanc, Dicomweb and QR have their own caches with directory tree
compatible to that of the SCP. A plugin cache directory setting can point to a corresponding subdirectory of
the SCP cache, then the plugin will pick up files sent to the SCP in advance.
The Listener can also automatically start the preparation of a received file. This works even with direct integration
plugins, at a cost of some disk space because the file is then received only for triggering the preparation (based
on UIDs from the file) and can be removed shortly afterwards; the preparation reads its own copy of the file from
the PACS file system. So far the direct integration plugins can’t reuse the SCP cache (for example, to avoid a
slower on-demand reading from network storage).
Note: Starting from 7.8.0, there is an alternative preparation trigger that saves both disk space and network
traffic: the PACS can send DICOM Instance Availability Notifications instead of files. (The Listener implements
both Store SCP and IAN SCP.)
Therefore for a significant performance boost one can configure the PACS to forward studies to MedDream, and
adjust related MedDream parameters:
# These two must be configured or else the Listener won't start up.
com.softneta.dicom-store-service.port=11116
com.softneta.dicomStoreService.acceptAETitles=pacs
# Cache root directory. A subdirectory with sender's AE Title (only values from
# acceptAETitles) is created automatically.
com.softneta.dicom-store-service.saveDirectory=file:///opt/meddream/temp/STORE/
# If true, then preparation jobs are executed; otherwise they remain in paused state
# after creation.
#True by default.
#com.softneta.preparation.enabled=true
# If true, the cache index is periodically saved into a file "cache.keys" under
# com.softneta.meddream.tempDir, and loaded during application startup.
# True by default since 8.0.0.
#com.softneta.preparation.persistCache=true
Warning: The .storeScpAet setting is used to find the plugin that will be used during preparation, and decide
whether the received file is to be removed afterwards.
If you have multiple plugins, then configure a different and not empty .storeScpAet for each plugin.
It might be required to assign some fake and non-realistic AETs. Consequently, a setup where the same
PACS is accessed both via a native plugin and via QR, becomes problematic as only one of them can upload
annotations/screenshots via the universal mechanism. Probably using .storageApiEnabled=true for the QR
plugin can help there, as the plugin will then use its own .remoteAET instead.
management.endpoint.prometheus.enabled=true
management.endpoints.web.exposure.include=prometheus
management.server.port=8081
management.server.address=127.0.0.1
scrape_configs:
- job_name: 'prometheus'
metrics_path: '/manage/prometheus'
scheme: 'http'
static_configs:
- targets: ['127.0.0.1:8081']
By default Prometheus listens on all IP addresses and port 9090. Like the status endpoint,
Prometheus itself should be available on localhost only. Address and port are changeable not
in prometheus.yml but via command line parameter --web.listen-addres (for example, in the
prometheus.service wrapper under Linux with systemd).
For a quick test, open http://127.0.0.1:9090/ on the server, enter “system_cpu_usage” as
Expression, press Execute and choose the Graph tab below.
4. Install Grafana on the same server as MedDream
See https://grafana.com/docs/grafana/latest/installation.
5. Add Prometheus as data source
Open http://localhost:3000/ in the browser. Choose “Add your first data source” on the first page.
Choose “Prometheus” from the list. Enter “http://localhost:9090/” as URL, and press the “Save &
test” button at end of the page. A message “Data source is working” should appear above.
See https://grafana.com/docs/grafana/latest/features/datasources/add-a-data-source for more
details.
6. Add a dashboard
Choose “Create your first dashboard” on the first page. Press the plus sign on the left and
choose “Import”. Under “Import via grafana.com”, enter 4701 (or 10280) and press Load. Specify
the data source created earlier, and press Import.
See https://grafana.com/docs/grafana/latest/reference/export_import for more details.
When the identity of a user without the “ADMIN” permission is known (the user has logged in via the login form, or
a HIS integration token provides the “id” field), then MedDream attempts to load a custom file <login>_global.
json.
If that fails, and the user belongs to one or more groups, then the first group name is chosen for the second
attempt with another custom file <group>_global.json.
As a last resort there is one more attempt with the traditional file global.json.
Note: Some settings, like Info Labels, are global by design and will be ignored in a per-user settings file. The
Settings window does not indicate that at the moment.
Note: The legacy “insecure” HIS integration (URL-based, not token-based) does not support user identities and
always uses the common global.json file.
Note: The user account that will use a custom settings file, must not have the “ADMIN” permission. A login
form account can have this permission individually like authorization.users[0].role=ADMIN, however a value
common to all users is possible in authorization.defaultLoginPermissions. In case of HIS integration, the
.permissions array in the token is the only possible source.
Note: If global.json was renamed via com.softneta.settings.globalFileName, then <login>_ is prepended to the
configured file name.
Starting from 8.1, a user with “USER_SETTINGS” permission (but without “ADMIN” permission) can save
to <login>_global.json directly, even if the file doesn’t exist yet. This implies that afterwards he won’t see any
changes made by the administrator to the common file global.json, as his own settings file is loaded first.
Starting from 8.2, a user with “SHORTCUTS_EDIT” permission can edit keyboard/mouse shortcuts. If “ADMIN”
is also present, then the global file shortcuts.json is edited, while users without “ADMIN” permission will save
to <login>_shortcuts.json instead. Furthermore, even without “SHORTCUTS_EDIT” the user will load an
existing individual file which then is read only.
8.2+ also keeps the hanging protocols settings in a separate file, hangingProtocols.json. The logic is
similar to that of shortcuts. Users with “ADMIN” permission are always editing this file. Other users can load
<login>_hangingProtocols.json in read only mode, and if the “HANGING_PROTOCOLS_EDIT” permission
is present, then this file becomes editable. If a user has “HANGING_PROTOCOLS_EDIT” instead of “ADMIN”,
and the individual file doesn’t exist yet, then it’s created when saving the hanging protocols settings.
As of 8.2, columns.json is not personalizable.
An administrator (who has the “ADMIN” permission) can only view/edit the common global.json file. If
giving the USER_SETTINGS permission is unsuitable due to some reason, then it is still possible to prepare
personalized read-only settings files as follows:
1. Make a copy of global.json.
2. Log in as an administrator (the account must have the “ADMIN” permission), open the Settings window,
make all planned changes and save the settings.
3. Rename the updated global.json to <login>_global.json. This <login> is an exact value of the user
name from the login form, or of .user.id from the HIS integration token. Leave the custom file in the same
directory.
4. Restore global.json from the copy.
5. To verify, log in as an ordinary user (without the “ADMIN” privilege) from the login form, or open a study
from HIS via the token.
The manual duplication steps above are valid not only for global.json but also for other personalizable settings
files.
Example of a HIS integration token with the login name:
{
"items": [
{
"studies": {
"study": "1.2.826.0.1.3680043.8.1055.1.2020050611210409.446757335",
"storage": "OrthancDicomweb"
}
}
],
"permissions": [ "PATIENT_HISTORY", "FORWARD", "DOCUMENT_VIEW" ],
"user": {
"id": "jdoe",
"name": "John Doe"
}
}
This token suggests using settings from the file jdoe_global.json, etc.
MedDream 8.2 offers customizable columns in the Patient History (opens from the thumbnail strip) and Patient
Studies (opens automatically in a certain token-based scenario). The Search window is not customizable so far.
Customization must also be supported by PACS integration plugins. So far those are only QR and Dicomweb
plugins.
A new file sys/settings/columns.json configures the GUI. The default contents are:
{
"patientHistoryColumns": [
{
"name": "openStudyColumn",
"parameters": [
"uid",
"storageId",
"sensitive",
"restricted"
],
"type": "openStudy",
"customClass": "flex-basis-9 center"
},
{
"name": "reportColumn",
"parameters": [
"hasReport"
],
"type": "report",
"customClass": "center"
},
{
"name": "patientId",
(continues on next page)
Values of “name” known to the GUI: openStudyColumn (special handling), reportColumn (special handling),
patientId, patientName, modality, description, dateTime, sourceAE.
Values of “parameters” (field names) known to the plugins: uid, storageId, sensitive (certain non-
public plugins only), restricted (certain non-public plugins only), hasReport (QR plugin only), patientId,
patientName, modality, description, date, time, sourceAE, receivedDate, custom1, custom2 . . . custom10.
At the plugin, the corresponding fields are set up like this (. . . columns.PARAMETER_NAME.*):
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.patientId.tag=1048608
#...
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.sourceAe.tag=1048624
com.softneta.meddream.pacs.configurations[PLUGIN_INDEX_NUMBER].columns.sourceAe.type=string
“parameters” in columns.json lists fields from the plugin that will be combined into the value (multiple parameters
are joined with a space character). At the plugin, . . . columns.PARAMETER_NAME.* configure what DICOM
attribute to use for this field (documentation of QR and Dicomweb plugins provides more details).
In some installations, especially Docker-based, it is more convenient to have a fixed application.properties file
where a few settings are missing, and pass those settings via environment variables instead.
For this to work, the environment variable must be named according to Spring Boot “relaxed binding” rules.
Example configuration variable: com.softneta.meddream.pacs.configurations[0].baseUrl.
Corresponding environment variable: COM_SOFTNETA_MEDDREAM_PACS_CONFIGURATIONS_0_BASE_URL.
PacsOne and Dicomweb plugins also support COM_SOFTNETA_MEDDREAM_PACS_CONFIGURATIONS_0_BASEURL etc.
(without any underscores as uppercase hints) in their variables.
Parameter Value
Identifier (Entity ID) https://MEDDREAM_URL/saml2/service-provider-metadata/
a8c544d-c442-4e94-aee4-2df9cb2992aa
Reply URL (Assertion Consumer https://MEDDREAM_URL/login/saml2/sso/a8c544d-c442-4e94-aee4-2df9cb2992aa
Service URL)
Sign on URL https://MEDDREAM_URL/saml2/authenticate/
a8c544d-c442-4e94-aee4-2df9cb2992aa
Azure doesn’t support plain HTTP hyperlinks, therefore either MedDream itself must use SSL, or you can use a
reverse proxy.
(Option 1) MedDream Viewer with SSL
Configure the following in application.properties for SSL:
server.ssl.key-store=${com.softneta.meddream.configRoot}/keystore.jks
server.ssl.key-store-password=password
server.ssl.key-alias=desktop-alias
security.require-ssl=true
server.port=443
spring.profiles.include=auth-saml
spring.security.saml2.relyingparty.registration.a8c544d-c442-4e94-aee4-2df9cb2992aa.
˓→assertingparty.metadata-uri=https://login.microsoftonline.com/a6a6746e-14bd-4e68-9c12-
˓→7593d8871c3c/federationmetadata/2007-06/federationmetadata.xml?appid=9a8c544d-c442-4e94-
˓→aee4-2df9cb2992aa
server.port=8080
server.use-forward-headers=true
server.forward-headers-strategy=native
server.tomcat.remote-ip-header=x-your-remote-ip-header
server.tomcat.protocol-header=x-your-protocol-header
spring.profiles.include=auth-saml
spring.security.saml2.relyingparty.registration.a8c544d-c442-4e94-aee4-2df9cb2992aa.
˓→assertingparty.metadata-uri=https://login.microsoftonline.com/a6a6746e-14bd-4e68-9c12-
˓→7593d8871c3c/federationmetadata/2007-06/federationmetadata.xml?appid=9a8c544d-c442-4e94-
˓→aee4-2df9cb2992aa
spring.security.saml2.relyingparty.registration.a8c544d-c442-4e94-aee4-2df9cb2992aa.acs.
˓→location=https://MEDDREAM_URL/login/saml2/sso/{registrationId}
Listen 443
<VirtualHost *:443>
ServerName MEDDREAM_URL
ServerAlias MEDDREAM_URL
ServerAdmin MEDDREAM_URL
SSLEngine on
SSLProxyEngine on
SSLCertificateFile "${SRVROOT}/conf/ssl/cert.crt"
SSLCertificateKeyFile "${SRVROOT}/conf/ssl/cert.key"
#MedDream
ProxyPreserveHost On
RequestHeader add X-Forwarded-Proto https
ProxyTimeout 800
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
ErrorLog "|bin/rotatelogs.exe -l logs/meddream.error.%Y.%m.%d.log 86400"
CustomLog "|bin/rotatelogs.exe -l logs/meddream.access.%Y.%m.%d.log 86400" common
</VirtualHost>
Log in to https://portal.azure.com with test user account which you have created when you set up Azure AD
SAML Toolkit, then go to Active Directory > Enterprise Applications. Choose “Azure AD SAML Toolkit” created
earlier. In Manage section choose Single sign-on.
Scroll down till you see section 5 Test single sign-on with Azure AD SAML Toolkit and press the Test button.
Select Sign in as current user and click Test sign-in button. It will open a new tab for sending login information
to Microsoft. Enter test user email address and password.
After a successful login, the page will change to MedDream Viewer search window.
(This is a summary that assumes the reader is already familiar with Keycloak. Please contact
[email protected] for the detailed version with screenshots.)
1. In Keycloak, create a Realm, a Client, at least one test user and export the certificate of that client.
2. Copy the exported certificate (files .crt and .key) to MedDream Viewer installation directory, for example,
C:\MDPACS\MedDream.
3. Add the following to application.properties
spring.profiles.include=auth-saml
authorization.defaultLoginPermissions=SEARCH,EXPORT_ISO,EXPORT_ARCH,FORWARD,
˓→REPORT_VIEW,REPORT_UPLOAD,PATIENT_HISTORY,UPLOAD_DICOM_LIBRARY,DOCUMENT_VIEW,
˓→FREE_DRAW_EDIT,BOUNDING_BOX_EDIT
spring.security.saml2.relyingparty.registration.REALM_NAME.signing.
˓→credentials[0].private-key-location=file:///C:/MDPACS/MedDream/myalias.key
spring.security.saml2.relyingparty.registration.REALM_NAME.signing.
˓→credentials[0].certificate-location=file:///C:/MDPACS/MedDream/myalias.crt
spring.security.saml2.relyingparty.registration.REALM_NAME.assertingparty.
˓→metadata-uri=http://KEYCLOAK_ADDR_PORT/realms/meddream/protocol/saml/
˓→descriptor
8.3.1 supports a “configuration server”: a cloud-dedicated mechanism where a separate JAR is running and
provides a fresh copy of application.properties for multiple MedDream instances. Currently you can run it on the
same machine for a single MedDream instance.
1. Create a dedicated subdirectory (for example, “C:\MDPACK\MedDream\configserver”). Move the file md-
config-server-0.0.1-SNAPSHOT.jar to that directory.
2. Create a couple of deeper subdirectories config/md (“C:\MDPACK\MedDream\configserver\config\md”)
and an empty file md.properties (not application.properties) there.
3. Copy storage definitions (PACS plugin configuration) from MedDream to this file. Another supported setting
is com.softneta.dicom-store-service.acceptAETitles. Other settings were not tested so far, and might
result in undefined behavior, or not apply as expected. For example,
com.softneta.dicom-store-service.acceptAETitles=PACS4
com.softneta.meddream.pacs.configurations[0].type=Dcm4chee2
com.softneta.meddream.pacs.configurations[0].id=d4c2Local
com.softneta.meddream.pacs.configurations[0].url=\
jdbc:mysql://172.16.32.11:3306/pacsdb
com.softneta.meddream.pacs.configurations[0].username=pacs
com.softneta.meddream.pacs.configurations[0].password=pacs
com.softneta.meddream.pacs.configurations[0].defaultStoragePath=\
(continues on next page)
com.softneta.meddream.pacs.configurations[1].type=FileSystem
com.softneta.meddream.pacs.configurations[1].id=files1
com.softneta.meddream.pacs.configurations[1].rootDirectory=C:\\upload
4. From the dedicated directory, start the JAR: java -Dspring.profiles.active=native -jar C:\MDPACS\
MedDream\md-config-server-0.0.1-SNAPSHOT.jar (include the full path to JRE executable if needed).
5. At MedDream side, add the following to application.properties (or change existing lines), then restart the
MedDream service:
authentication.manager.username = admin
authentication.manager.password = <USE A STRONG PASSWORD>
management.endpoints.enabled-by-default = true
management.endpoints.web.exposure.include = refresh
This is similar to other parts of this Manual which also suggest configuring manager’s credentials
and exposing some management endpoints. For this scenario a strong password and the
endpoint name “refresh” are sufficient.
6. After adding more plugin configurations at the configuration server (C:\MDPACK\MedDream\configserver\
config\md\md.properties), or changing the acceptAETitles setting there, make a POST call to
<MedDream URL>/manage/refresh, with the configured credentials passed via Basic Authentication.
The configuration will refresh immediately. After reloading the GUI in browser, or logging in anew,
you’ll see the updated set of storages.
Current limitations:
• MedDream requires at least one plugin in order to start, therefore you can’t begin with no plugin
configurations in its application.properties. Include at least one initially (at both sides), then add more
at the configuration server.
• Plugin configurations present in MedDream’s application.properties can’t be removed via the configuration
server. Furthermore, their copies should always remain in md.properties to avoid unexpected and hard to
troubleshoot behavior.
For example, a particular plugin was defined as the second one (...[1]) and you remove the
first one. Then this new [0] coming from configuration server will be merged with the original [0]
at MedDream, which means overwriting properties with the same names.
The configuration server starts on port 8888, and MedDream expects it there. If this port can’t be used on your
machine, then more configuration is necessary. Suppose you chose the port 12345:
• create a dedicated application.properties file in the configuration server’s directory (C:\MDPACK\MedDream\
configserver\application.properties) and add a single server.port setting:
server.port=12345
spring.config.import=configserver:http://127.0.0.1:12345
Troubleshooting incomplete configuration is more difficult when a service is involved. You should first make sure
that MedDream already works as expected when Java Core is started from a console window.
5.2.1. Windows
Note: The variable BASEDIR in the script is dynamically initialized with the directory of the script itself. This
means that you must leave the script near the JAR file, and place only a softlink in /etc/init.d, like in the above
example. The entire script can be copied to /etc/init.d only if you adjust BASEDIR, too.
As Debian-like systems don’t have chkconfig, the last command can be replaced with sudo update-rc.d
meddream defaults.
By changing the line USER=root in {INSTALL_DIRECTORY}/meddream, you can force a less privileged user that
can still access DICOM files etc. However this will likely require updating the line PIDF=/var/run/$PROG.pid,
too, as /var/run is usually a privileged location (a chown’ed subdirectory will suffice in that case).
The file {INSTALL_DIRECTORY}/meddream also contains the JRE command line, for example:
˓→PropertiesLauncher"
To configure the Token Service this way, change the file names and command parameters accordingly:
• /opt/token-service/token-service.redhat or /opt/token-service/token-service.debian is copied
to /opt/token-service/token-service;
• in the console,
[Unit]
Description=MedDream Viewer
After=syslog.target
[Service]
WorkingDirectory=/opt/meddream
User=root
ExecStart=/usr/bin/java -cp MedDream-8.3.1-dev.jar -Xmx1G -Dloader.path=./sys/plugins -Djava.
˓→library.path=./lib -DANTLR_USE_DIRECT_CLASS_LOADING=true --add-opens=jdk.management/com.
˓→sun.management.internal=ALL-UNNAMED --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED --
˓→add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.management/com.sun.jmx.
˓→mbeanserver=ALL-UNNAMED --add-opens=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED --
˓→add-opens=java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens=java.
˓→springframework.boot.loader.PropertiesLauncher
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
Note: Update User=root with the actual username under which the Java application will run.
To configure the Token Service this way, change the names accordingly: the file is /etc/systemd/system/token-
service.service, and contains
[Unit]
Description=MedDream Token Service
After=syslog.target
[Service]
(continues on next page)
[Install]
WantedBy=multi-user.target
˓→opens=jdk.management/com.sun.management.internal=ALL-UNNAMED --add-opens=java.base/jdk.
˓→management/com.sun.jmx.mbeanserver=ALL-UNNAMED --add-opens=jdk.internal.jvmstat/sun.
˓→jvmstat.monitor=ALL-UNNAMED --add-opens=java.base/sun.reflect.generics.
˓→desktop/sun.awt.image=ALL-UNNAMED org.springframework.boot.loader.PropertiesLauncher
To configure the Token Service this way, change the names accordingly: the file is /home/{user
name}/.config/upstart/token-service.conf and contains
Suppose you already went through the 5.1.1 Essential configuration and the first run chapter, configured the
authentication method and PACS plugins, set up Java applications as services, adjusted system.json and even
read the 5.1.9 Reference for remaining configuration parameters superficially.
This is a good opportunity for initial security tightening (see 7 Security considerations, especially the “Summary”
part). If during that process you accidentally disable too much of MedDream functionality, this will be noticed in
subsequent steps.
Afterwards it’s time for a final functionality check-up.
• For installations with an interactive login and Search window:
– The login form does not produce an error message and is successfully replaced by the Search
window. An administrative login (with the ADMIN permission) also succeeds and gives access to
the Settings window.
Remember that the login form is unavailable by default (results in “403 Forbidden” message)
if no authentication method is configured.
In 7.5.1+, there is no sense to have an interactive login if the Search window is disabled (the
text “404” on dark background, due to features.search=false in system.json).
Even if the integration doesn’t offer a working search functionality, you might still decide to
keep the window enabled, at least for a short time – for convenient access to the Settings
window via an administrative login.
– The Search window shows studies from every configured PACS plugin (except FileSystem).
* Results can be restricted by date interval, Patient ID, etc. Keep in mind, however, that some
plugins do not support returning some fields at all, and some plugins do not support filtering by
some returned fields.
* If the plugin supports filtering by user identity, then results are different depending on who is
logged in. Consult configuration of the PACS and MedDream for a suitable identity.
– If Export or Forward are enabled (both globally and by current user’s permissions), then the operation
can be started from the Search window and succeeds.
• For all installations:
– Opening a study succeeds: thumbnails are displayed instead of exclamation marks, the chosen image
opens as well.
Choose the studies wisely and cover at least different modalities.
* Export (both its versions, “Burn” and “Export”, also including the reports as PDFs),
* Forward,
* Share to DICOM Library,
* Oblique MPR,
* display of PDFs and SRs,
* the expected set of measurements is available.
Repeat with less-privileged users if any exist.
– Verify that the example “demo” / “demo” user account is not present any more.
– The Core service (and the token validation service, if used) starts successfully after rebooting the
entire machine.
– If rebranding is used, then the About window etc. looks as expected.
– Info Label and Thumbnail size settings correspond to end users’ requirements. Changing these two
settings often is not desired: it might also require cleaning of temporary files at the server, therefore
studies will again open slower like during the first time.
• For HIS integration installations:
– In case of “unsafe” integration, check if every enabled URL parameter (“study” etc.) results in opening
of the right studies. If the “storage” parameter is not listed in the validHisParams setting, it will be
silently ignored.
– In case of token-based integration, also check whether MedDream correctly handles all integration
options implemented in your HIS: expected set of object identifiers (“study”, “accnum”, etc. – no
less and no more), token-specified patient history, permission overrides, object restrictions (like by
Patient ID), one-time tokens, limited-lifetime tokens. This will obviously involve different tokens and
experiments at the HIS side.
– If MedDream is supposed to open in an IFRAME at your webpage, then also attempt to open it from
the dedicated network and using the dedicated server hostname.
• For integration into PacsOne web interface:
– MedDream successfully opens from the list of studies (not from the list of patients, series or images).
– Multiple studies are allowed. You should know how many of them the users might want, and configure
the limit accordingly.
– After MedDream opens this way, the expected set of features (Export, Reporting, etc.) is still available
to all users.
A few first days after going online can involve multiple restarts of the Core service. Each restart can leave a
lot of unused temporary files that will be removed some time later. The cleanest way to verify this removal is to
lower every “olderThanSec” setting (for example, to 1 second) temporarily and confirm that all accumulated files
disappear. Nevertheless monitoring of the disk space is still advised.
We provide two ready-to-use Docker images that might save you some time, especially during evaluation. See
• https://hub.docker.com/r/meddream/dcm4chee-dicom-viewer for DCM4CHEE 5.x, or
• https://hub.docker.com/r/meddream/orthanc-dicom-viewer for Orthanc.
After purchasing a commercial license or more concurrent connections, it is necessary to update the license file
(meddream.lic).
On installations with an Internet connection, the “Register” window is sufficient. MedDream will automatically
download the file and place it where appropriate. The new file comes into effect immediately, though restarting
the service is still recommended.
In other cases you must update meddream.lic manually:
• by default it resides in the same directory as application.properties or meddream*.jar, likely it’s /opt/
meddream or C:\MedDreamPACS-Premium\MedDream;
• in dockerized installations a dedicated subdirectory is often used, like /opt/meddream/license – that way
it’s easier to store any changes outside the container;
• when in doubt, look for com.softneta.license.licenseFileLocation in application.properties. If this setting is
not present, it defaults to the directory of the JAR file.
Restarting the service is mandatory after a manual update.
MedDream 8.1+ has the “Clear cache” function for interactive removal of a single study (or series, or image) from
the preparation cache. It must be enabled globally in system.json (features.clearCache=true) and for a particular
user (CLEAR_CACHE permission). This mechanism, however, does not yet extend to DICOM files cached by
some plugins.
The entire preparation cache will need cleaning if:
• you changed the setting com.softneta.preparation.compressPixelsBeforeSave;
Currently the setting controls whether the pixels are cached in compressed or non-compressed
form, and the frontend attempts decompression based on its value (instead of detecting the
existing format). As a result, cached pixels become incompatible after changing the setting.
• you changed the settings Thumbnail size or Info Label properties (the latter, in turn, might be affected by
personNameConfiguration in system.json);
Thumbnails are generated and cached using the configured size, and their appearance on
studies opened earlier might become suboptimal after changing the size.
Info Labels are generated and cached using the configured patterns. This includes a particular
person name format configured elsewhere. Changed patterns will be visible only on studies that
haven’t been opened before.
Plan ahead when choosing the values, as losing many days’ worth of prepared files might be
too costly.
• trackDicomModifications in application.properties is off and some DICOM files have been changed on
the PACS.
For example, PacsOne supports modification of certain DICOM attributes and this is done not
only in the database but in the files, too. The operation updates the file timestamps, therefore
trackDicomModifications=true in case of direct integration is enough for automatic regeneration.
Modalities are an unlikely reason, as they normally use new UIDs after changing patient
demographics etc. in a study that has already been sent to the PACS.
The default location of the preparation cache is “temp/cache” in the directory of the JAR file. Your installation
might redefine it directly via com.softneta.preparation.cacheDir; if only com.softneta.meddream.tempDir is
redefined, then a subdirectory “cache” under it is used by default. To confirm that it’s the right one, examine
the contents: you should see a storage subdirectory (same as .id in configuration of a PACS plugin), then three
two-digit subdirectories like 6f/3e/1b, then a long subdirectory like 89a44027269f77b1cb3948290635077461 and
various files below it.
After removing the cached files, the MedDream service must be restarted in some cases.
1. Open H2 Console in the browser, then a corresponding database there (see 5.1.10 Opening the H2
Console for details).
2. Execute the command SCRIPT TO 'db-backup.sql', where “db-backup.sql” can have any name and
extension (an SQL file is always created), and wait for its completion.
By default the file is created in the same directory as the application JAR file; you should be able
to use any other writeable location, too, like /tmp/export.sql or d:\temp\backup.sql.
3. Disable the Console afterwards.
Note: The restore process will destroy current database contents. If in doubt, make a backup.
A binary backup is sufficient. A rather simple way is to copy the database file (it has an extension .mv.db) when
the MedDream service is stopped.
1. Open H2 Console in the browser, then a corresponding database there (see 5.1.10 Opening the H2
Console for details).
2. Remove all content by using the command DROP ALL OBJECTS.
3. Execute the command RUNSCRIPT FROM 'db-backup.sql', using the relevant path to a dump file. Make
sure there are no errors reported.
4. Restart the application so that it has the opportunity to upgrade the database schema, then verify the
functionality related to this database.
5. Disable the Console afterwards.
Passwords with special characters, like NN"A_B7;Q{G\.}q5+XTuw=^q, can be difficult to enter correctly in SQL
queries (“IDENTIFIED BY” clause, “SELECT PASSWORD(. . . )” query, etc.) because some characters must be
escaped or else their meaning becomes different. As a result, the password might not be accepted afterwards
even by the same MySQL client.
A workaround is to use an online MySQL password calculator/generator that is entirely browser-based (does not
perform a request to the server during the calculation), then enter the resulting hash into the query that updates
the password.
At the time of this writing (January 2023), we can recommend https://www.browserling.com/tools/
mysql-password; it yields *6BED9D9BC91C5F5994B2F7D4AE105E2E5BBC262F for the example string above.
6. Additional software
MedDream can be used in tandem with several external pieces of software that are listed below.
A plugin for the Chrome browser that expands a newly opened tab across several monitors. The URL is scanned
for an entered keyword and if a match is found, a new window is created and expanded across the selected
monitors. The plugin can be added using the Chrome extensions tab.
When using the plugin, it is important to give the MedDream website the “window placement” or “window
management” permission. When opening MedDream for the first time on a particular browser, you should
get a prompt that the website wants “manage windows on all your displays”, then click “Allow”. If you clicked
“Block” back then, this can be adjusted by clicking the “lock” icon near the URL, choosing “Site settings” and
looking for “Window management” there.
To obtain the plugin, please contact [email protected].
The legacy solution “MedDreamBurn” is/was for writing ISOs to optical disks. There is no direct equivalent for
writing to USB sticks.
It might be possible, however, to work around using these freeware alternatives:
• ISO to USB (http://www.isotousb.com/) – no command line support and therefore not possible to start
automatically with an ISO file already specified; you will need to specify the file manually. Because
formatting removable media is a privileged operation, Windows UAC prompt might be triggered on every
start.
• Rufus (https://rufus.ie/en/) – again no command line support. Might require a bootable ISO file although
MedDream never creates these.
On Windows it might be enough to use the built-in functionality for writing optical disks:
• Right-click on the file (ISO or BURN) and select “Open With”.
• Select “Choose another app”.
• Select “More apps”.
• Scroll to the bottom and select “Look for another app on this PC”.
• Browse to folder C:WindowsSystem32 and select isoburn.exe
• Click Open.
From now on clicking on those files will start the built-in burner. You might also want to select the checkbox
“Open when done” while the file is still being downloaded.
7. Security considerations
RATIONALE: It is an old dilemma of using “security through obscurity”. As a matter of fact, most MedDream
installations tend to have a few security holes due to non-paranoid Web administrators. The very publication of
this knowledge makes every old/unmaintained MedDream installation an easy target. But we must draw a line
one day so that at least new installations are secure.
The default application.SAMPLE.properties sets up “in-memory” authentication method with a username “demo”
and password “demo”. It is included only to ease installation and might be known to everyone who has
downloaded a recent MedDream release.
Do not forget to change it (or remove altogether) after the installation is finished.
User-agent: *
Disallow: /
User-agent: AdsBot-Google
Disallow: /
This should prevent finding Internet-exposed MedDream login forms by searching for “MedDream” or “Softneta”
(as most customers don’t use rebranding). Afterwards an attacker could check for known issues or
misconfigurations.
If you still would like to index your installation, or allow indexing for a particular search engine only,
then sys/settings/robots.txt can be modified accordingly (see http://www.robotstxt.org/robotstxt.html) or even
renamed/removed. The backend treats the file as a static anonymous resource and simply returns contents
of the file if it is found.
Official installation instructions offer some defaults that sometimes are left unchanged.
After a mindless installation there also will be some default user accounts:
• a database user “pacs” with password “pacs”. Suitable for MedDream when using auth-db-connection;
• an internal user “admin” with password “admin” – suitable for MedDream and DCM4CHEE’s web interface
when using auth-dcm4chee;
• an internal user “user” with password “user” – suitable for MedDream and DCM4CHEE’s web interface
when using auth-dcm4chee.
Any of these accounts can be used to access sensitive patient data. We suggest to change passwords for all
three, as soon as possible after the installation. The first one is used by DCM4CHEE to connect to the database,
therefore you will also need to update the file server/default/deploy/pacs-*-ds.xml (name depends on database
used).
Availability to embed MedDream into FRAME, IFRAME or OBJECT containers allows untrusted websites to use
MedDream in fraudulent manner (“clickjacking”). Since v6.2.1 this is restricted by default: only the server that
hosts MedDream is allowed to wrap it with an additional container.
It is possible to adjust IFRAME permissions in the application.properties file. Valid values for
frameOptionsPolicy: NONE, DENY, SAMEORIGIN, ALLOW-FROM. When NONE is used, then the X-Frame-
Options and Content-Security-Policy headers are not sent; when ALLOW-FROM is used, then valid host must be
set in parameter security.frameOptionsWhitelist. Another parameter, security.contentSecurityPolicy,
can be used to explicitly control the Content-Security-Policy header. Address entries are separated using spaces.
security.frameOptionsPolicy=POLICY_VALUE
security.frameOptionsWhitelist=IP_ADDRESS or HOST_ADDRESS
#security.contentSecurityPolicy = frame-ancestors 'self' IP_ADDRESS HOST_ADDRESS
7.5. php.ini
When the same machine also contains a PHP/Apache installation (needed by third-party software like PacsOne),
then some PHP settings might make it less secure. This chapter lists most important recommendations and
caveats.
Error handling
• expose_php = Off
The value “Off” hides the version of PHP from webserver response headers or error messages
and therefore makes it more difficult to scan for known vulnerabilities of PHP itself.
• error_reporting = E_ALL
“E_ALL” is recommended for production. However during installation/troubleshooting of any
server, including a production one, a more detailed choice like “E_ALL | E_STRICT” might be
needed. One could have two versions of this line and comment the inactive one out.
• display_errors = Off
• display_startup_errors = Off
Use “Off” in production for both, or else error messages visible to the end user might reveal paths
to files and other sensitive information.
• track_errors = Off
Can remain disabled as MedDream’s applet.php doesn’t use $php_errormsg.
• html_errors = Off
“On” is not needed and, due to display_errors=Off, has no effect anyway.
• log_errors = On
• error_log = /valid_path/PHP-logs/php_error.log
Logging to a file is preferred over STDERR. The latter means Apache’s error_log where PHP
messages will be intermixed with Apache messages and therefore harder to read.
• ignore_repeated_errors = Off
“On” is OK only as a temporary measure if there are lots of identical errors, they are filling up the
log and nothing else can be done about that right now.
General settings
• doc_root = /PacsOneInstall/php
In 7.5+, the only part of MedDream served over the Web is applet.php when copied to PacsOne’s
“php” directory. In this configuration you can specify this directory or some parent part of the path.
• open_basedir = /PacsOneInstall/php
Not relevant to MedDream anymore.
A non-empty setting provides more benefits (and influence) to other software, like PacsOne GUI,
running on the same Apache server. Take caution and test all functionality.
• include_path = .:/path/PHP-pear/
Keep this list as short as possible. This setting is not related to applet.php of MedDream, but
might be used by other software if hosted on the same server.
• extension_dir = /path/PHP-extensions/
Use a full path.
This parameter is not relevant to MedDream any more.
• mime_magic.magicfile = /path/PHP-magic.mime
Use a full path.
Not relevant to MedDream anymore. When using MedDream with PacsOne on the same host,
PacsOne might still benefit on correct value.
• allow_url_fopen = Off
“On” is not required by MedDream 7.5+.
• allow_url_include = Off
• allow_webdav_methods = Off
“Off” for both is safer and doesn’t interfere with any MedDream functionality.
• variables_order = "GPCS"
A general recommendation, not relevant to MedDream anymore.
• session.gc_maxlifetime = 600
Not relevant to MedDream anymore as sessions are now handled at Java side. Will influence
behavior of PacsOne GUI, though.
A smaller value will log the user off faster if the browser is closed, the computer is suspended or
the Internet connection is cut. 10 minutes is a sane default and the legacy default is 1440 (24
minutes).
File uploads
• file_uploads = Off
MedDream 7.5+ does not contain PHP-based Reporting functionality so this setting doesn’t
apply.
“On” might be important for PacsOne, though, as its Study Notes and Upload Dicom Image
functions work in a similar way.
• upload_tmp_dir = /path/PHP-uploads/
Use a full path. A separate directory might make cleaning leftover files easier.
• upload_max_filesize = 10M
• post_max_size = 40M
Files larger than upload_max_filesize will fail to upload. To account for overhead, ensure
post_max_size > 4*upload_max_filesize and memory_limit > 16*post_max size.
• max_file_uploads = 1
PacsOne always uploads a single attachment together with a Study Note so “1” is a safe choice.
Executable handling
• enable_dl = Off
Not relevant to MedDream anymore, and “Off” is a safer choice.
• disable_functions = system, shell_exec, passthru, phpinfo, show_source,
highlight_file, fopen_with_path, dbmopen, dbase_open, putenv, exec, popen, proc_open,
move_uploaded_file, mkdir, rmdir, chmod, rename, chdir, filepro, filepro_rowcount,
filepro_retrieve, posix_mkfifo
These functions are generally considered dangerous and applet.php of MedDream does not use
them. However, some might be needed for proper functioning of PacsOne. Take caution and test
the configuration.
Session handling
• session.save_path = /path/PHP-session/
Use an absolute path. This will ensure that both Apache-integrated and CLI versions of PHP
keep session files in the same location.
• session.name = mysessid
You can rename the session cookie to something less obvious.
Not relevant to MedDream anymore but other software on the same Apache server might benefit
from this.
• session.auto_start = Off
Not relevant to MedDream anymore, and “Off” is a safer choice.
• session.use_trans_sid = 0
• session.use_cookies = 1
• session.use_only_cookies = 1
Not relevant to MedDream anymore, and “Off” is a safer choice. Take care with PacsOne, though.
• session.cookie_domain = my.website.tld
Not relevant to MedDream anymore, and “Off” is a safer choice. Take care with PacsOne, though.
• session.use_strict_mode = 1
“1” or “On” is more secure. There is no effect on MedDream functionality in any case.
• session.cookie_lifetime = 0
Zero is the legacy value (the session exists while the browser is not closed) and end users are
accustomed to it. This is more relevant to PacsOne than MedDream.
• session.cookie_secure = 1
Not relevant to MedDream anymore. If Apache also hosts other software that is accessed only
via HTTPS (plain HTTP is undesirable), then set this to “1”.
• session.cookie_httponly = 1
“1” is a general recommendation. Not relevant to MedDream anymore, but might influence other
software if hosted on the same server.
• session.cache_expire = 30
Not relevant to MedDream anymore but might influence other software if hosted on the same
server.
• session.cookie_samesite = Strict # PHP 7.3+
• session.sid_length = 256 # PHP 7.1+
• session.sid_bits_per_character = 6 # PHP 7.2+
• session.hash_function = 1 # PHP 7.0-7.1
• session.hash_bits_per_character = 6 # PHP 7.0-7.1
The above values are recommended and are understood by newer PHP versions.
• session.referer_check = http://server/path
Not relevant to MedDream anymore but might influence other software if hosted on the same
server. For PacsOne, you can set here a typical URL pointing to its GUI (directories only, without
home.php etc).
Less obvious settings
• memory_limit = 50M
• max_execution_time = 30
Not relevant to MedDream anymore. The setting provides more benefits (and influence) to other
software running on the same Apache server.
• report_memleaks = On
“On” might help to detect memory leaks earlier. Not relevant to MedDream anymore.
MedDream is designed with “zero footprint” concept in mind. From a security perspective this also means that no
patient data is left on a client machine: after the end user logs out from MedDream, its cache does not contain
any server responses with patient data.
Normally browsers obey the “do not cache” headers. Firefox, however, has a bug that allows to extract potentially
sensitive data from browser’s memory cache after the user logs out and doesn’t close the entire browser
application. On a shared computer, an attacker could later examine the memory cache and access data that
isn’t available to him via MedDream and HIS.
Shared computers make protecting sensitive data a lot more difficult. If this is unavoidable, then we recommend
at least to avoid Firefox or teach users to also close the entire browser (not just a particular tab or one of the
windows) after logging out from MedDream.
7.7. Firewalls
Every server, especially the ones that handle medical data, should have a working firewall.
MedDream obviously needs permission to listen at port configured by server.port for a typical HTTP(s) traffic.
When using websockets (system.json: features.liveShare=true, or openTabsTrackingMethod=SOCKETS), they
operate over the same port.
Similarly, the receiver for QueryRetrieve plugin will continuously listen at com.softneta.dicomStoreService.
port for a typical DICOM traffic.
Outgoing network accesses might need to be whitelisted in a corporate firewall:
• the Register function downloads a license file from lic.softneta.com;
• the About window verifies availability of a new version at www.softneta.com;
• the Share function sends anonymized files to dicomlibrary.com.
• The MedDream installation package must be validated against the SHA-256 value published at
softneta.com. (Scanning it with VirusTotal, https://www.virustotal.com/, is a good idea, too.)
– Windows: certutil -hashfile MedDream-DICOM-Viewer-8.3.1.zip SHA256
– Linux: sha256sum MedDream-DICOM-Viewer-8.3.1.zip
– Mac OS: shasum -a 256 MedDream-DICOM-Viewer-8.3.1.zip
If the displayed hash is the same as provided on the website for that file, then the file has been
downloaded without corruption and can be used safely.
The hash can also be downloaded as a separate file with the extension “.sha256” instead of “.zip”:
https://www.softneta.com/files/meddreamviewer/820/MedDream-DICOM-Viewer-8.3.1.sha256
• The operating system should be up to date with latest security patches.
• All not needed software should be removed from the system to reduce points of possible security breaches.
• Use the latest Java 17 version with all security patches.
• Server version should be hidden in HTTPS responses.
• Open only those firewall ports that are necessary to access MedDream (default Web port 80 or 443, and
default DICOM port 11116 if used) or PACS servers.
• For HIS integration the secure token-based integration is highly recommended, instead of the legacy URL
integration.
• The MedDream backend should not run under a privileged user, like Linux “root” user or Windows
“Administrators” user group.
• MedDream files should have limited permissions (Linux example: 0775 for files, 0664 for directories).
• The MedDream backend should always run over HTTPS (with SSL encryption). Do not use self-signed
certificates; if your company doesn’t have one, then https://letsencrypt.org/ will provide it for free.
• Main security-related settings in application.properties:
– server.servlet.session.cookie.sameSite = strict
– server.servlet.session.cookie.secure = true
– security.xssProtectionDisabled = false
– security.contentTypeOptionsDisable = false
– security.contentSecurityPolicy = default-src 'self'; style-src 'self'
'unsafe-inline'; script-src 'self'; child-src 'self' blob:; connect-src 'self' *;
img-src 'self' data:; worker-src 'self' blob:;
– server.servlet.session.timeout – set a reasonable duration based on network and system
performance.
– authentication.manager.* should be disabled. Enable it only for a short amount of time, and use a
strong password (see below).
– management.server.port = 8081 (or similar) together with management.server.address = 127.0.
0.1, if some software is monitoring the status of MedDream.
– spring.profiles.include = auth-inmemory, authentication.inmemory.*, authorization.
users[] should not be used in production configuration.
• MedDream should use strong passwords everywhere: at least 12 characters with uppercase, lowercase,
numbers, special characters, and not listed in https://haveibeenpwned.com/Passwords.
• User roles must be only those that are absolutely necessary for a particular user. Less roles = more strict
and safe account.
Warning: If the IT security is compromised, MedDream does not guarantee any functionality. If there is a risk
that a security issue can impact patient safety or cause sensitive data leak, then it is recommended to stop
using product as soon as possible until the issue is resolved. Depending on the risk impact (for example, when
the issue can not impact patient safety or leak sensitive data), the medical device user can continue using the
device on his own risk. However it is recommended to have an external standby system (redundant, spare
system) which could provide full functionality (or part of it) instead of the compromised system. MedDream
product is fully compatible with the possibility to deploy one or more offline/online standby systems to increase
healthcare process safety, security and reliability.
Warning: “InMemory” users are recommended to use only for testing proposes. In production, please use
DB users or token authentication.
If you found that IT security is compromised, for Emergency work while the system will be fixed we
recommend to create InMemory user(s) with needed permissions: for an administrator, add ADMIN and
SEARCH permissions; for ordinary users, add the SEARCH permission.
Note: MedDream does not detect a change of the client IP address during the session. There are legitimate
cases when this change is possible (for example, because a mobile device is moving).
8. Localization
By default, MedDream is available in English, Lithuanian and Russian; user documentation is only in English.
Warning: Softneta is not responsible for not verified translations made by licensed users. Please note that
Medical Device certificates are not valid for not verified translations.
The default value of “languages” setting in sys/settings/system.json is just “en”. You can specify any available
language or their combination. For example, :["en"] can be changed to :["lt","en","ru"].
9. Rebranding
MedDream can be rebranded and use custom branding information (e.g., logos, product name, some certification
details). Four scenarios are possible:
1. No rebranding was the default in older licenses (v7.8.0 and older). MedDream displays the default logo
pictures, while “Distributor” and “End user” data come from the license;
2. Simple rebranding is usually enabled and allows to change logotypes, system name, default color theme;
3. Full rebranding (also called “Rebranding as a module”, requires a special license) allows to change more
options, however these changes will invalidate CE, FDA and other medical certificates;
4. Viewport rebranding can be used together with Viewports API, where a large portion of MedDream
user interface is not present and can be implemented by the customer. Additional analysis is required to
determine which parts of the product will be certified, please contact [email protected] for assistance.
Since 7.9, the product version number can’t be rebranded and MedDream will always check for the latest version.
All rebranding-related files must be located in the directory sys/settings/rebranding/ below configRoot. The
configuration file is “rebranding_configuration.json”, it must be in valid JSON format (UTF-8, no comments, no
embedded newlines).
An override for the Web resource /favicon.ico is always expected under a name “favicon.ico”. This file must
exist if the license allows rebranding.
Example configuration file for simple rebranding:
{
"systemName":"MyHospital",
"companyLogoFile":"companylogo.jpg",
"productLogoFile":"productlogo.jpg",
"loginLogoFile":"loginlogo.jpg",
"defaultTheme": "red"
}
• systemName
(optional) Name of the system into which MedDream is integrated. Displayed at top of About
dialog if not empty, and overrides the product name in browser tab titles, below login form and
below search results.
• companyLogoFile
Name of a JPG/PNG file with the company logo displayed in the About dialog.
Recommended size is 134 x 28 px. Images wider than 540 pixels do not always fit into the dialog.
A too high image might move the buttons outside the screen so the dialog becomes unusable.
Make sure to check your customization on various client systems (different display DPI, etc.)
from where MedDream will be opened.
• productLogoFile
Name of a JPG/PNG file with the product logo displayed in Wiewer window (top left corner).
Recommended size is 180 x 38. In the viewer the height can be up to 52 px, anything more is
clipped; if the width exceeds 215 px, the rest will overlap with thumbnails. When your picture is
near these limits, it might need checking on various client systems to ensure consistent behavior.
• loginLogoFile
Name of a JPG/PNG file with the login logo displayed in Login window.
Maximum dimensions are 270 x 50. Wider images will not be centered. Higher images will shift
the form towards the bottom of the page.
• defaultTheme
(optional) Selects a predefined color theme from values red (default), blue, green, dark-blue,
dark-green, orange.
The default rebranding configuration strives to provide the same look of MedDream as in not rebranded
installations.
Remaining configuration options are used in rare cases:
• productName
(Required when full rebranding) Replaces the text “MedDream” in the bottom of the login
window, the “Product” part of the About dialog, the title of the browser tab, below login form and
below search results.
For ordinary licenses (rebranding without isUsedAsModule), the product name comes from the
license.
Example:
"productName":"MyViewer"
• manufacturedBy
(Optional, full rebranding only) When true, the Distributor contacts from the license are
displayed as “Manufactured By”.
Example:
"manufacturedBy":true
• uniqueDeviceId
(Optional, full rebranding only) Displayed as “Unique device identifier” in the About dialog.
Consult your certification documents.
Example:
"uniqueDeviceId":"444444455"
• medicalDeviceClass
(Optional, full rebranding only) Displayed as “Medical device class” in the About dialog.
Typically includes both class and legislation where this class is defined; consult your certification
documents.
Example:
"medicalDeviceClass":"Example Class"
• notifiedBodyId
(Optional, full rebranding only) Displayed as “ID of the notified body” in the About
dialog. Consult your certification documents. A related image at the bottom is taken from
md5/css/icons/certification-logo2.png when rebrandCertified=true.
Example:
"notifiedBodyId":"0123"
• rebrandFdaClarification
(Optional, full rebranding only) Displayed as “FDA Cleared” in the About dialog. Consult your
certification documents. A related image at the bottom is taken from md5/css/icons/certification-
logo.png when rebrandCertified=true.
Example:
"rebrandFdaClarification":"FDA Cleared B12345"
• rebrandCertified
(Optional, full rebranding only) When true, md5/css/icons/certification-logo.png and
md5/css/icons/certification-logo2.png are still displayed despite rebranding.
Example:
"rebrandCertified":true
• catalogueNumber
(Optional, full rebranding only) Displayed as “Catalogue number” in the About dialog.
Hardcoded value “MDSY” when the license does not allow full rebranding.
• mobileDisplayLimitations
(Optional, full rebranding only) Displayed as “Warning” in the About dialog.
Hardcoded value “about.mobileDisplayLimitations” (a particular translation code) when the
license does not allow full rebranding.
• showRepresentativesInfo
(Optional, full rebranding only) Enable display of the “REP” tab in the About dialog.
Hardcoded value true when the license does not allow full rebranding.
• safetySign
(Optional) Object with additional properties for overriding the warning/caution/note symbols and
a corresponding comment in the About dialog:
– warning
Name of the warning icon file (in the same directory as JSON file).
For full rebranding, there is no default image and this setting must be configured in
order to display an icon.
For other kinds of rebranding, a default image is displayed if this setting is not
configured.
– caution
Name of the caution icon file (in the same directory as JSON file).
For full rebranding, there is no default image and this setting must be configured in
order to display an icon.
For other kinds of rebranding, a default image is displayed if this setting is not
configured.
– note
Name of the note icon file (in the same directory as JSON file).
For full rebranding, there is no default image and this setting must be configured in
order to display an icon.
For other kinds of rebranding, a default image is displayed if this setting is not
configured.
– safetySignDescription
(Optional, full rebranding only) Any text about the safety signs.
Hardcoded value “about.safetySignDescription” (a particular translation code) when
the license does not allow full rebranding.
The files md5/css/md.*.css are minified and difficult to navigate. You should pretty print the chosen file first, even
free online tools like https://www.cleancss.com/css-beautify/ can handle that.
The following example changes the color in the de-minified “default” theme to pure yellow:
10. Troubleshooting
10.1. Preventive measures
The most important step in preventing problems is monitoring, especially for some time just after the installation.
System administrators should regularly watch:
• amount of free space on disks used by MedDream;
Currently MedDream does not stop creating temporary files if amount of free space is
dangerously low, and will proceed until its amount drops to zero. This might result in corrupt
databases (reindexing usually takes a long time) or corrupt cached files (difficult to identify which
ones are corrupt, and too costly to remove everything). If other software is using the same disks,
it might get similar issues. To minimize impact, it is quite important to timely react to low disk
space situations.
The size of temporary/cached files is proportional to user activity. In some installations the daily
amount of new studies sent to the PACS might have a larger influence. Both are not constant
and MedDream therefore might need a periodic review of data age thresholds in temporary files
cleaner configuration. But sometimes the only solution is to add more storage.
{"status":"UP","components":{"licensing":{"status":"UP","details":{"cc":1}},
˓→"ping":{"status":"UP"}}}
Excessive virus scanning may severely impact performance. There is no sense to scan the MedDream
preparation cache (com.softneta.preparation.cacheDir, or “cache” under tempDir by default) so this directory
tree should be excluded, especially when using the in-advance preparation and expecting a large amount of
data there.
You should also consider whitelisting the DICOM files themselves on the PACS. Even if some are routinely
uploaded over a custom Web interface, their on-demand scanning in a corresponding temporary directory (before
importing to the PACS) might be more adequate.
In the directory of the Java application, the file meddream.main.log will be created.
To control the overall logging level, adjust the following line in application.properties:
logging.level.root=DEBUG
logging.level.org.hibernate=DEBUG
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
spring.jpa.show-sql=true
logging.level.org.springframework.security=DEBUG
Logic of the temporary files cleaner is spread among the following modules:
logging.level.com.softneta.meddream.service.temp.TempCleanerService=DEBUG
logging.level.com.softneta.meddream.util.PathUtils=DEBUG
logging.level.com.softneta.meddream.util.DirTreeRemover=DEBUG
Dicomweb and Orthanc plugins depend on the following third-party library that can display HTTP
request/response headers (but not POST data):
logging.level.sun.net.www.protocol.http=DEBUG
logging.level.com.softneta.pacs.gateway.plugin.pacsone=DEBUG
logging.level.com.softneta.pacs.gateway.plugin.dcm4chee5=DEBUG
logging.level.com.softneta.pacs.gateway.plugin.dcm4chee2=TRACE
logging.level.com.softneta.pacs.gateway.plugin.clearcanvas=DEBUG
logging.level.com.softneta.pacs.gateway.plugin.conquest=TRACE
logging.level.com.softneta.pacs.gateway.plugin.orthancplugin=TRACE
logging.level.com.softneta.pacs.gateway.plugin.dicomweb=DEBUG
logging.level.com.softneta.pacs.gateway.plugin.qr=TRACE
logging.level.com.softneta.pacs.gateway.plugin.filesystem=DEBUG
logging.level.com.softneta.pacs.gateway.plugin.amazon.s3=DEBUG
The levels listed above correspond to the maximum level used by a particular plugin.
When troubleshooting cache behavior, it is sometimes needed to know what UIDs are hidden beyond
those random-looking subdirectories, like .../bb/b2/ef/eedc376fdb0d545d9344b67092ee2e78d2/meta. This
is revealed by
logging.level.com.softneta.meddream.util.HashedPath=TRACE
Unfortunately, there will be a lot of corresponding messages, as they appear multiple times even when loading
a single-image study.
Under Windows, the MedDream.exe service wrapper duplicates the logged information into files
MedDream.err.log and MedDream.out.log. The latter is sometimes more informative than meddream.main.log,
and its size can be controlled separately. To adjust the size and number of files MedDream.out.*.log, add the
<log> element to MedDream.xml, then modify its sizeThreshold and keepFiles:
<log mode="roll-by-size">
<sizeThreshold>10240</sizeThreshold>
<keepFiles>10</keepFiles>
</log>
</service>
When a video file is being converted to MPEG4, then stdout and stderr of the FFmpeg process are
redirected to a troubleshooting file ${com.softneta.video.convertedDir}/<SOP Instance UID><storage
ID>.out; the converted video goes to a temporary file ${com.softneta.video.convertedDir}/<SOP Instance
UID><storage ID>.tmp.mp4. When FFmpeg finishes, the temporary file is renamed to the final version, ${com.
softneta.video.convertedDir}/<SOP Instance UID><storage ID>.mp4. By default convertedDir points to a
subdirectory “temp/converted-videos”.
The conversion has no formal time limit. But, while the temporary file still exists, its modification time should
always be recent (which is the case if FFmpeg still writes to it). If the time doesn’t change for more than 120
seconds, then MedDream assumes FFmpeg is likely stuck or its wrapper script has crashed, and attempts to
remove all related files (.out, .tmp.mp4, .mp4).
On success the troubleshooting file is removed, and the final file is moved to the preparation cache for later use.
On failure both files remain for analysis. An empty final file is considered a failure, too.
Since 8.2.0 subsequent retries are not possible (the converter doesn’t even start) while the final file
(*.mp4) still exists. You must remove it manually in order to try again. The suggested configuration of Temporary
files cleaner removes any files under convertedDir older than one hour, every 30 minutes.
You can choose a location on your computer where downloads should be saved by default or pick a specific
destination for each download.
• On your computer, open Chrome.
• At the top right, click More and then Settings.
• At the bottom, click Advanced.
• Under the “Downloads” section, adjust your download settings:
• To change the default download location, click Change and select where you’d like your files to be saved.
• If you’d rather choose a specific location for each download, check the box next to “Ask where to save each
file before downloading”.
If you didn’t change your default download location, then Google Chrome downloads files to the following
locations:
• Windows 10, 8, 7 and Vista: \Users\<username>\Downloads
• Mac: /Users/<username>/Downloads
• Linux: /home/<username>/Downloads
Note: Changing the location of your downloads affects all downloaded files in this Web browser.
• Click the menu icon on the top right corner of the browser.
• Click Preferences.
• Click General.
• Click Choose. . . next to Save files to.
10.5.4. Safari
The buttons “Copy the image to the clipboard” and “Copy measurements to the clipboard” become hidden if the
conditions below are not met:
1. the connection must be HTTPS or to a “localhost” address (when MedDream is opened on the server
itself). This is a limitation in all Web browsers;
2. Firefox also requires dom.events.asyncClipboard.clipboardItem with value “true” in about:config. This
setting must be created or adjusted on every client machine;
3. when MedDream is integrated into another website via an IFRAME, then the latter must have the
allow="clipboard-read; clipboard-write" attribute. This, however, is a server side change.
Note: Proper display of color images usually requires the “sRGB” color profile set up in the browser. For
Chrome, this can be changed at the chrome://flags/#force-color-profile page.
If you suspect that the monitor does not show small differences in brightness, especially at the dark or at the
bright end of the entire range, then the first step is to confirm the problem using third-party resources:
• https://www.photofriday.com/info/calibrate
• http://www.lagom.nl/lcd-test/
10.8. Symptom: on Linux the loading pauses just after logging in,
possibly with wrong webpage colors
On some Linux installations, the Java backend might pause for up to several minutes when a new concurrent
connection is made. Immediately after the login, the user sees either an empty dark page with a progress bar
spinning at the top, or an empty white page, or a white page with a black-and-white DEMO message.
The cause: the default configuration of OpenJDK suggests reading from /dev/random that can block due to
exhausted entropy pool. Some systems are refilling the pool more slowly so this problem becomes more
common.
Solution 1: add -Djava.security.egd=file:///dev/./urandom to the command that starts the Java backend.
Refer to the 5.2 Running as a service chapter for hints where this command might be located.
It is recommended to stop the service, then start the updated command manually and verify the effect. You
might want to force entropy exhaustion so that the problem appears as soon as possible; use dd if=/dev/
random of=/dev/null bs=512 count=1 for that (on a different terminal as it will block, too).
Solution 2: the above might still not help with some OpenJDK builds, therefore you’ll need to update system-
wide configuration in the java.security file (traditionally it’s $JAVA_PATH/jre/lib/security/java.security):
securerandom.source=file:///dev/./urandom
10.9. Symptom: queries to MS SQL Server take seconds from Java but
milliseconds from Management Studio
A very poor performance was observed in a particular installation of Conquest over ODBC,
even for simple queries by object UID. Adding sendStringParametersAsUnicode=false; to
com.softneta.meddream.pacs.configurations[].url fixed that.
The default true means that all query parameters are sent to server as NVARCHAR, even for columns of
VARCHAR type. The type conversion results in a full table scan so performance with large tables drops down.
If correct representation of non-Latin characters is important, then you should leave true and the database
schema should use NVARCHAR in all MedDream query key columns (including UIDs). When national characters
are not used, then false is a more simple solution.
Some DICOM MPEG4 videos play on recent Chrome and Edge browsers but not on Firefox under Windows.
The “loading” animation (spinning dots in a circle) is displayed forever, the browser’s console contains “Decoder
may not have the capability to handle the requested video format with YUV444 chroma subsampling”. Older
Firefox versions tell that the file is corrupt.
Unfortunately, Firefox team claims that under Windows support is not possible due to legal limitations. This video
format might provide a higher image quality.
If too many end users of yours can’t use another browser, then you should force a format downgrade by adding
-pix_fmt yuv420p to FFmpeg command line. Afterwards all browsers will encounter the more popular 4:2:0
chroma format, and there will no benefit for those that support 4:4:4.
Example for software encoder (default command line) with this additional parameter:
By design, Share to DICOM Library does not send the following objects in “Active study” mode:
• those that are hidden due to blackListedSopClasses in system.json, and due to another hardcoded list of
known unsupported SOP Classes;
• old versions of Bounding Box, Free Draw and Smart Paint annotations.
If they are important, then one should use the Export function and upload the resulting archive to DICOM Library
manually.
Note: Names marked with # (for example, “#datasource.quartz”) are internal properties, not to be changed by
the end user. Most of them are also not offered in application.SAMPLE.properties to discourage any changes.
security.meddreamProxyIp
Also supports a hostname, which will be resolved to an IP address.
authorization.remapRoles.*
Now supported in case of auth-pacsone.
Names of PacsOne groups to which the user belongs are fetched from the database, and can used in
parameters “authorization.remapRoles.GROUP_NAME” to add some more MedDream permissions.
However group’s own privileges assigned in PacsOne GUI are ignored.
com.softneta.preparation.additionalMetadataTags
List of custom tags cached for the “metadata” endpoint which is used by the “V2” implementation
(experimental) of hanging protocols.
com.softneta.dicomParser.additionalPrivateTags
List of private tags that won’t be ignored during parsing. Might be needed for additionalMetadataTags
to function properly.
com.softneta.preparation.skipStructurePreparation
Disables queries to the PACS during preparation if studyStructureSec > 0 ir pgwStudyResponseSec
> 0.
com.softneta.meddream.dcmsnd.annotationsFromOrigAet
When sending annotations to the PACS, in some cases MedDream can use the original AE Title
already associated with the study. (Tested only with PacsOne plugin; will definitely not work with
DCM4CHEE2 plugin.)
security.detectRemoteIpChange
It is possible to detect the change of client’s IP address and log a warning or invalidate the session.
com.softneta.study.lowerPrioritySeriesModalities
Reordering of study structure: series with modalities listed here will be moved to the end.
The effect is similar to sCSeriesLowerPriority setting of Dicomweb plugin, however might be more
effective/flexible and works for all plugins.
eventApiEnabled
Controls “Clean cache” at the plugin side when caching is enabled for PacsOne installations that
store studies on AWS S3.
dicomCacheDirectory
In this directory the plugin will cache DICOM files downloaded from AWS S3 so that subsequent
accessses are faster and do not contribute to the traffic cost.
awsS3Marker
A magic value used to detect that PacsOne has stored the DICOM file on S3 instead of a local disk.
Likely hardcoded in PacsOne.
awsS3Separator
The character that separates awsS3Marker from the remaining path. Likely hardcoded in PacsOne.
awsS3ConnectionInfoCacheTimeInSec
AWS S3 bucket and region identifiers extracted from the database will be reused for this many
seconds.
mv /opt/meddream /opt/meddreamBKP
Warning: You might be tempted to simply copy the old application.properties to the new
version and then review it. This is not recommended:
• A higher risk of keeping settings not supported any more, which might lead to confusion
later.
• No opportunity to encounter default values (or totally new settings) in
application.SAMPLE.properties that are safer security-wise, especially if overlooked.
• No opportunity to encounter comments/explanations that might be more comprehensive
in newer versions of application.SAMPLE.properties.
7. If, however, your application.properties is made from scratch instead, then consult Appendix: Configuration
changes since 8.3.0 or even the entire list 5.1.9 Reference for remaining configuration parameters.
8. If rebranding is used, then for every setting in the new sys/settings/rebranding/rebranding_configuration.json,
copy the value from a setting in the old version.
If the old file does not contain the same setting, then consult Rebranding. It might be renamed
or totally new.
Afterwards copy all referenced image files from the old sys/settings/rebranding directory to the
new one.
9. Update file permissions (example below is for MedDream running as user “meddream”):
Warning: Unmodified system.json from older versions might be incompatible and result in a
crash when starting the JAR.
If you went the non-recommended way and are upgrading in-place, then old files
sys/database/*.mv.db might prevent the JAR from starting, too. In case of errors related to
H2 database engine, these files must be moved elsewhere so that new ones can be created.
11. Open the Settings window, review/adjust the configuration and save it. Without
toolbarButtonsOrderingEnabled = false, the ordering of toolbar buttons and actions might differ from
the saved one, and this new order will be forced until settings are manually reordered and saved by the
new version.
Warning: You might be tempted to simply copy the old application.properties to the new
version and then review it. This is not recommended:
• A higher risk of keeping settings not supported any more, which might lead to confusion
later.
• No opportunity to encounter default values (or totally new settings) in
application.SAMPLE.properties that are safer security-wise, especially if overlooked.
• No opportunity to encounter comments/explanations that might be more comprehensive
in newer versions of application.SAMPLE.properties.
9. If, however, your application.properties is made from scratch instead, then consult Appendix: Configuration
changes since 8.3.0 or even the entire list 5.1.9 Reference for remaining configuration parameters.
10. If rebranding is used, then for every setting in the new sys\settings\rebranding\rebranding_configuration.json,
copy the value from the old version.
If the old file does not contain the same setting, then consult Rebranding. It might be renamed
or totally new.
Afterwards copy all referenced image files from the old sys\settings\rebranding folder to the new
one.
11. If MedDream is running under some dedicated user, reapply the “Modify” permission for this user on
C:\MDPACS\MedDream and all its contents.
12. Start the JAR so that sys\settings\system.json is created automatically. For every setting, copy the value
from the old system.json. Consult the documentation (5.1.2 System.json) and list of configuration changes
(Appendix: Configuration changes since 8.3.0).
Warning: Unmodified system.json from older versions might be incompatible and result in a
crash when starting the JAR.
If you went the non-recommended way and are upgrading in-place, then old files
sys\database\*.mv.db might prevent the JAR from starting, too. In case of errors related to
H2 database engine, these files must be moved elsewhere so that new ones can be created.
13. Open the Settings window, review/adjust the configuration and save it. Without
toolbarButtonsOrderingEnabled = false, the ordering of toolbar buttons and actions might differ from
the saved one, and this new order will be forced until settings are manually reordered and saved by the
new version.