Migration to Dicoogle 3
Dicoogle 3 was released in 2019, with the purpose of taking down obsolete constructs and bringing new features which improve the archive’s overall performance. This page will guide users and developers towards migrating their PACS and extension software for the major version 3 of Dicoogle.
For Dicoogle User
As a PACS infrastructure maintainer or administrator, the following points will cover what you need to know.
Java 8 is the minimum supported version
Dicoogle 2 still worked on a Java 7 runtime, but it has been obsolete for a long time. Dicoogle 3 requires Java 8, and should also work on Java 11. Support for more recent versions is slowly being incorporated, but for now it is recommended to use either 8 or 11.
New server settings file
The server settings file has been redesigned to become easier to read and contain new properties. It is still an XML file, and it bears multiple similarities with the old format. Many properties have been renamed, and new ones were brought in. Properties which were no longer useful were removed as well.
Typically though, no special intervention is needed.
When booting, Dicoogle 3 will migrate an existing config.xml
file
to use the new format, and save it in confs/server.xml
.
If you validate that the migration was successful,
the file config.xml
is then safe to remove.
Users file must be recreated
The file users.xml
keeps track of registered users in the archive,
including their roles and privileges.
In Dicoogle 3, this file’s semantics were changed
to use a stronger password hashing algorithm.
This makes a users.xml
file in a Dicoogle 2 installation incompatible,
and must not be transferred into Dicoogle 3.
Instead, let Dicoogle create a new users file
and insert new users if necessary.
It is also possible to encrypt this file
so that the list cannot be tampered nor viewed
if the configuration file becomes compromised.
If this option is enabled in the configuration file
mentioned in the previous section,
then the file name will be called users.xml.enc
instead of users.xml
.
Plugins for Dicoogle 2 are not compatible with Dicoogle 3
The plugin-based extension framework will expect plugins made for the same major version of the Dicoogle SDK. As such, the old plugins that were used in Dicoogle 2 must not be directly copied to a Dicoogle 3 deployment, because that is not going to work.
The appearance of the following error message on boot is a sign that at least one plugin is incompatible:
Exception in thread "main" java.lang.SecurityException: sealing violation: package pt.ua.dicoogle.sdk is sealed
If you are not the developer, you will need to reach out to the maintainers of the plugins and request that they are ported to work on Dicoogle 3.
For Dicoogle Developers
As a developer of extensions for Dicoogle, here are the main changes to keep in mind.
Update dicoogle-sdk
The major version of dicoogle-sdk needs to match
with the target Dicoogle platform.
Look for the respective dependency
element in your pom.xml
file
and update accordingly.
<dependency>
<groupId>pt.ua.ieeta</groupId>
<artifactId>dicoogle-sdk</artifactId>
<version>3.0.2</version>
</dependency>
Remove PluginSet#getGraphicalPlugins
The Graphical plugin type has been non-functioning since early Dicoogle 2,
but the methods for their retrieval were not removed.
So, getGraphicalPlugins
must be completely removed in all plugin sets.
In order to develop extensions to the user interface, see the section on Web UI plugins.
Server settings API with changes
If your plugin was fetching the server’s settings
via the Dicoogle platform interface,
the object returned is now significantly different,
and so some changes may be needed.
See the ServerSettingsReader
class for more information.
New method StorageInterface#list
The new method list
provides a shallow list of entries
given a URI representing a directory.
This is different from the method at
,
which would make a full, nested traversal of all files in that directory.
Users of this method still need to assume that
it may throw UnsupportedOperationException
,
as this is what the default implementation does.
When carefully checked,
it can be used to make quick estimations of
a process covering an entire directory,
or to obtain a tree-like vision of the storage.
User creation Web API changes
Creating new users via the Web API must now be done with the POST method instead of PUT.
Example:
POST {root}/user?username=johndoe&password=secret
Be sure to update all integration software to follow the matching specification of the Web API.
No automatic query processing
In Dicoogle 2, when a user wrote a free text query on the search bar
without any field (keyword) terms such as CT
,
that query would be preprocessed to search for that content
by multiple known DICOM attributes
(SOPInstanceUID, StudyInstanceUID, SeriesInstanceUID,
AccessionNumber, Modality, PatientID, PatientName,
and many others).
For instance, the query PID123
would expand into a boolean union query
which included the term PatientID:PID123
and many others,
thus capturing the files which had PID123
in one of these attributes.
This process would also replace certain characters such as ^
into whitespace,
as it was often desirable when searching by person names.
In Dicoogle 3, this preprocessing is no longer done.
The /search
endpoint still has the old behavior
behind the expand
query string parameter,
but it is not used by the web application.
This is because query processing
should be under full control of the query provider itself,
and often the existing process was either unnecessary
or even detrimental to a good query provider behavior.
Implementers of query providers which are also a source of DICOM data may want to incorporate some form of query preprocessing internally if they wish for free text queries to work like before. Query providers based on Lucene only need the right document construction logic and indexing configurations for these queries to work without any form of query expansion.
QueryInterface#query
can throw QueryException
The new exception type QueryException
is specifically for when a query could not be performed.
This allows consumers to make a distinction between errors with the given query
and other kinds of errors.
For implementers, a good place to throw QueryException
is when the parameter query
is syntactically incorrect.
New extended trait QueryDimInterface
Query interface objects may now also implement QueryDimInterface
.
This extended form provides a way
to query at different levels in the DICOM Information Model.
Before this interface, consumers of plain query interfaces wishing to obtain a list of studies had to retrieve a list of images and aggregate them manually, which can be unnecessarily expensive in studies with a large number of files.
With QueryDimInterface
, when specifying a specific DIM level,
each search result will refer to a single instance at that level,
making searches less expensive.
In practice, you would want to use instanceof
to check whether a given query interface object implements it.
There is currently no utility method in the Dicoogle platform interface
to invoke these operations asynchronously.
if (queryInterface instanceof QueryDimInterface) {
((QueryDimInterface) queryInterface).queryStudy("StudyInstanceUID:1.2.3.4.555");
// ...
}
Default implementations for interface getters
Most methods in the plugin set now have default implementations which do nothing or return an empty list of plugins:
getIndexPlugins
getQueryPlugins
getStoragePlugins
getRestPlugins
getJettyPlugins
shutdown
If your plugin project does not have any plugins of a specific type,
it is safe to remove these methods,
as they are redundant.
In the case of shutdown
,
it can be removed if it was going to be left empty anyway.
New way to inject platform interface
In Dicoogle 2,
plugin sets and respective plugin implementations
would retrieve the Dicoogle platform interface
by adding implements DicoogleCommunicatorInterface
to the class
and overriding the method setPlatformProxy
.
In Dicoogle 3,
there is an alternative which requires less code:
add a non-static field of type DicooglePlatformInterface
to the class
and add the annotation @pt.ua.dicoogle.sdk.annotation.InjectPlatformProxy
.
public class MyPluginSet implements PluginSet {
@InjectPlatformProxy
private DicooglePlatformInterface platform;
}
The field will be set by Dicoogle automatically, some time after construction during the plugin loading phase.
The previous way of obtaining a proxy to the platform interface still works. Note that, as was before, only plugin sets and plugins registered by those sets can obtain this interface through these two mechanisms.