001/*
002 * *** BEGIN LICENSE BLOCK *****
003 *  Version: MPL 1.1/GPL 2.0/LGPL 2.1
004 *
005 *  The contents of this file are subject to the Mozilla Public License Version
006 *  1.1 (the "License"); you may not use this file except in compliance with
007 *  the License. You may obtain a copy of the License at
008 *  http://www.mozilla.org/MPL/
009 *
010 *  Software distributed under the License is distributed on an "AS IS" basis,
011 *  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012 *  for the specific language governing rights and limitations under the
013 *  License.
014 *
015 *  The Original Code is part of dcm4che, an implementation of DICOM(TM) in
016 *  Java(TM), hosted at https://github.com/gunterze/dcm4che.
017 *
018 *  The Initial Developer of the Original Code is
019 *  Agfa Healthcare.
020 *  Portions created by the Initial Developer are Copyright (C) 2015
021 *  the Initial Developer. All Rights Reserved.
022 *
023 *  Contributor(s):
024 *  See @authors listed below
025 *
026 *  Alternatively, the contents of this file may be used under the terms of
027 *  either the GNU General Public License Version 2 or later (the "GPL"), or
028 *  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
029 *  in which case the provisions of the GPL or the LGPL are applicable instead
030 *  of those above. If you wish to allow use of your version of this file only
031 *  under the terms of either the GPL or the LGPL, and not to allow others to
032 *  use your version of this file under the terms of the MPL, indicate your
033 *  decision by deleting the provisions above and replace them with the notice
034 *  and other provisions required by the GPL or the LGPL. If you do not delete
035 *  the provisions above, a recipient may use your version of this file under
036 *  the terms of any one of the MPL, the GPL or the LGPL.
037 *
038 *  ***** END LICENSE BLOCK *****
039 */
040
041package org.dcm4che3.conf.dicom;
042
043import org.dcm4che3.conf.api.DicomConfiguration;
044import org.dcm4che3.conf.api.TCConfiguration;
045import org.dcm4che3.conf.api.TCGroupsProvider;
046import org.dcm4che3.conf.api.TransferCapabilityConfigExtension;
047import org.dcm4che3.conf.api.internal.DicomConfigurationManager;
048import org.dcm4che3.conf.core.api.ConfigurationException;
049import org.dcm4che3.conf.core.Nodes;
050import org.dcm4che3.data.UID;
051import org.dcm4che3.net.ApplicationEntity;
052import org.dcm4che3.net.Device;
053import org.dcm4che3.net.TCGroupConfigAEExtension;
054import org.dcm4che3.net.TransferCapability;
055import org.slf4j.Logger;
056import org.slf4j.LoggerFactory;
057
058import java.util.*;
059
060/**
061 * Relies on org.dcm4che3.net.TCGroupConfigAEExtension and TransferCapabilityConfigExtension to load Transfer Capabilities
062 *
063 * @author Roman K
064 */
065public class AlternativeTCLoader {
066
067    private static final Logger log =
068            LoggerFactory.getLogger(AlternativeTCLoader.class);
069
070    private final DicomConfigurationManager config;
071    private final boolean doCacheGroups;
072
073    private TCConfiguration tcGroups;
074
075
076    public AlternativeTCLoader(DicomConfigurationManager config, boolean doCacheGroups) {
077        this.config = config;
078        this.doCacheGroups = doCacheGroups;
079    }
080
081
082    private TCConfiguration getTCConfig() throws ConfigurationException {
083
084        TCConfiguration tcGroups = null;
085        if (doCacheGroups) {
086            tcGroups = this.tcGroups;
087        }
088
089        if (tcGroups != null && tcGroups.getTransferCapabilityGroups() != null && tcGroups.getTransferCapabilityGroups().size() > 0) {
090            return tcGroups;
091        }
092        return this.tcGroups = config.getDicomConfigurationExtension(TransferCapabilityConfigExtension.class).getTransferCapabilityConfig();
093    }
094
095
096    void initGroupBasedTCs(Device d) throws ConfigurationException {
097
098        TCConfiguration tcConfig = getTCConfig();
099
100        for (ApplicationEntity applicationEntity : d.getApplicationEntities()) {
101            TCGroupConfigAEExtension tcGroupConfigAEExtension = applicationEntity.getAEExtension(TCGroupConfigAEExtension.class);
102            if (tcGroupConfigAEExtension != null) {
103
104                // override any entries that might have been added before
105                applicationEntity.setTransferCapabilities(new ArrayList<TransferCapability>());
106
107                // Always add CEcho SCP
108                applicationEntity.addTransferCapability(new TransferCapability("CEcho SCP", UID.VerificationSOPClass, TransferCapability.Role.SCP, UID.ImplicitVRLittleEndian));
109
110                // add processed TCs from pre-configured groups to this ae
111                for (Map.Entry<String, TCGroupConfigAEExtension.TCGroupDetails> tcGroupRefEntry : tcGroupConfigAEExtension.getScpTCs().entrySet())
112                    addTC(applicationEntity, tcConfig, tcGroupRefEntry, TransferCapability.Role.SCP);
113                for (Map.Entry<String, TCGroupConfigAEExtension.TCGroupDetails> tcGroupRefEntry : tcGroupConfigAEExtension.getScuTCs().entrySet())
114                    addTC(applicationEntity, tcConfig, tcGroupRefEntry, TransferCapability.Role.SCU);
115
116            }
117        }
118    }
119
120
121    @SuppressWarnings("Duplicates")
122    private void addTC(ApplicationEntity applicationEntity, TCConfiguration tcConfig, Map.Entry<String, TCGroupConfigAEExtension.TCGroupDetails> tcGroupRefEntry, TransferCapability.Role role) throws ConfigurationException {
123        TCConfiguration.TCGroup tcGroup = tcConfig.getTransferCapabilityGroups().get(tcGroupRefEntry.getKey());
124
125        if (tcGroup == null) {
126            log.error("Transfer capability group " + tcGroupRefEntry.getKey() + " not found");
127            return;
128        }
129
130        for (TransferCapability tc : tcGroup.getTransferCapabilities()) {
131
132            TCGroupConfigAEExtension.TCGroupDetails tcGroupDetails = tcGroupRefEntry.getValue();
133
134            // exclude TC if blacklisted
135            if (tcGroupDetails.getExcludedTransferCapabilities().contains(tc.getSopClass()))
136                continue;
137
138            TransferCapability tcModified = tc.deepCopy();
139            tcModified.setRole(role);
140            tcModified.setCommonName(tcModified.getCommonName() + " " + role);
141
142            // handle exclusions/whitelisting
143            ArrayList<String> tsList = new ArrayList<String>(Arrays.asList(tcModified.getTransferSyntaxes()));
144            Iterator<String> iterator = tsList.iterator();
145            if (tcGroupDetails.getWhitelistedTransferSyntaxes() != null &&
146                    !tcGroupDetails.getWhitelistedTransferSyntaxes().isEmpty()) {
147
148                // use whitelisting logic if enabled - remove all but the specified TSs
149                while (iterator.hasNext())
150                    if (!tcGroupDetails.getWhitelistedTransferSyntaxes().contains(iterator.next()))
151                        iterator.remove();
152            } else {
153
154                // otherwise just filter out excluded TSs
155                while (iterator.hasNext())
156                    if (tcGroupDetails.getExcludedTransferSyntaxes().contains(iterator.next()))
157                        iterator.remove();
158            }
159
160            // add TC only if there is at least one TS left after filtering
161            if (!tsList.isEmpty()) {
162                tcModified.setTransferSyntaxes((String[]) tsList.toArray(new String[]{}));
163                applicationEntity.addTransferCapability(tcModified);
164            }
165        }
166    }
167
168    public void cleanUpTransferCapabilitiesInDeviceNode(Device device, Map<String, Object> deviceNode) {
169        Nodes.removeNodes(deviceNode, DicomPath.AllTCsOfAllAEsWithTCGroupExt.path());
170    }
171
172    public void refreshTCGroups() {
173        tcGroups = null;
174    }
175}