001/* ***** BEGIN LICENSE BLOCK ***** 002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 003 * 004 * The contents of this file are subject to the Mozilla Public License Version 005 * 1.1 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * http://www.mozilla.org/MPL/ 008 * 009 * Software distributed under the License is distributed on an "AS IS" basis, 010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 011 * for the specific language governing rights and limitations under the 012 * License. 013 * 014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in 015 * Java(TM), hosted at https://github.com/gunterze/dcm4che. 016 * 017 * The Initial Developer of the Original Code is 018 * Agfa Healthcare. 019 * Portions created by the Initial Developer are Copyright (C) 2011 020 * the Initial Developer. All Rights Reserved. 021 * 022 * Contributor(s): 023 * See @authors listed below 024 * 025 * Alternatively, the contents of this file may be used under the terms of 026 * either the GNU General Public License Version 2 or later (the "GPL"), or 027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 028 * in which case the provisions of the GPL or the LGPL are applicable instead 029 * of those above. If you wish to allow use of your version of this file only 030 * under the terms of either the GPL or the LGPL, and not to allow others to 031 * use your version of this file under the terms of the MPL, indicate your 032 * decision by deleting the provisions above and replace them with the notice 033 * and other provisions required by the GPL or the LGPL. If you do not delete 034 * the provisions above, a recipient may use your version of this file under 035 * the terms of any one of the MPL, the GPL or the LGPL. 036 * 037 * ***** END LICENSE BLOCK ***** */ 038 039package org.dcm4che3.net; 040 041import java.io.*; 042import java.util.Arrays; 043import java.util.EnumSet; 044import java.util.Set; 045 046import org.dcm4che3.conf.core.api.ConfigurableClass; 047import org.dcm4che3.conf.core.api.ConfigurableProperty; 048import org.dcm4che3.conf.core.api.LDAP; 049import org.dcm4che3.data.UID; 050import org.dcm4che3.util.StringUtils; 051import org.dcm4che3.util.UIDUtils; 052 053/** 054 * DICOM Standard, Part 15, Annex H: Transfer Capability - The description of 055 * the SOP classes and syntaxes supported by a Network AE. 056 * <p> 057 * An instance of the <code>TransferCapability</code> class describes the 058 * DICOM transfer capabilities of an SCU or SCP in terms of a single 059 * presentation syntax. This includes the role selection (SCU or SCP), the 060 * acceptable transfer syntaxes for a given SOP Class, and any extra 061 * information. 062 * 063 * @author Gunter Zeilinger <gunterze@gmail.com> 064 * 065 */ 066@LDAP(objectClasses = {"dicomTransferCapability", "dcmTransferCapability"}) 067@ConfigurableClass 068public class TransferCapability implements Serializable { 069 070 private static final long serialVersionUID = 6386251434418693778L; 071 072 public enum Role { SCU, SCP } 073 074 private ApplicationEntity ae; 075 076 @ConfigurableProperty(name="cn") 077 private String commonName; 078 079 @ConfigurableProperty(name="dicomSOPClass") 080 private String sopClass; 081 082 @ConfigurableProperty(name="dicomTransferRole") 083 private Role role; 084 085 @ConfigurableProperty(name="dicomTransferSyntax") 086 private String[] transferSyntaxes; 087 088 @LDAP( booleanBasedEnumStorageOptions = {"dcmRelationalQueries","dcmCombinedDateTimeMatching","dcmFuzzySemanticMatching","dcmTimezoneQueryAdjustment"}, 089 noContainerNode = true) 090 @ConfigurableProperty(name = "dcmQueryOptions", enumRepresentation = ConfigurableProperty.EnumRepresentation.ORDINAL) 091 private EnumSet<QueryOption> queryOptions; 092 093 @LDAP(noContainerNode = true) 094 @ConfigurableProperty(name = "dcmStorageOptions") 095 private StorageOptions storageOptions; 096 097 public TransferCapability() { 098 this(null, UID.VerificationSOPClass, Role.SCU, UID.ImplicitVRLittleEndian); 099 } 100 101 public TransferCapability(String commonName, String sopClass, Role role, 102 String... transferSyntaxes) { 103 setCommonName(commonName); 104 setSopClass(sopClass); 105 setRole(role); 106 setTransferSyntaxes(transferSyntaxes); 107 } 108 109 public void setApplicationEntity(ApplicationEntity ae) { 110 if (ae != null) { 111 if (this.ae != null) 112 throw new IllegalStateException("already owned by AE " + 113 this.ae.getAETitle()); 114 } 115 this.ae = ae; 116 } 117 118 /** 119 * get the name of the Transfer Capability object. Can be a meaningful name 120 * or any unique sequence of characters. 121 * 122 * @return A String containing the common name. 123 */ 124 public String getCommonName() { 125 return commonName; 126 } 127 128 public void setCommonName(String commonName) { 129 this.commonName = commonName; 130 } 131 132 /** 133 * Get the role for this <code>TransferCapability</code>instance. 134 * 135 * @return Role (SCU or SCP) for this <code>TransferCapability</code>instance 136 */ 137 public Role getRole() { 138 return role; 139 } 140 141 public void setRole(Role role) { 142 if (role == null) 143 throw new NullPointerException(); 144 145 if (this.role == role) 146 return; 147 148 ApplicationEntity ae = this.ae; 149 if (ae != null) 150 ae.removeTransferCapabilityFor(sopClass, this.role); 151 152 this.role = role; 153 154 if (ae != null) 155 ae.addTransferCapability(this); 156 } 157 158 /** 159 * Get the SOP Class of this Transfer Capability object. 160 * 161 * @return A String containing the SOP Class UID. 162 */ 163 public String getSopClass() { 164 return sopClass; 165 } 166 167 public void setSopClass(String sopClass) { 168 if (sopClass.isEmpty()) 169 throw new IllegalArgumentException("empty sopClass"); 170 171 if (sopClass.equals(this.sopClass)) 172 return; 173 174 ApplicationEntity ae = this.ae; 175 if (ae != null) 176 ae.removeTransferCapabilityFor(sopClass, this.role); 177 178 this.sopClass = sopClass; 179 180 if (ae != null) 181 ae.addTransferCapability(this); 182 } 183 184 /** 185 * Get the transfer syntax(es) that may be requested as an SCU or that are 186 * offered as an SCP. 187 * 188 * @return list of transfer syntaxes. 189 */ 190 public String[] getTransferSyntaxes() { 191 return transferSyntaxes; 192 } 193 194 public void setTransferSyntaxes(String... transferSyntaxes) { 195 if (transferSyntaxes.length == 0) 196 throw new IllegalArgumentException("missing transferSyntax"); 197 for (String ts : transferSyntaxes) 198 if (ts.isEmpty()) 199 throw new IllegalArgumentException("empty transferSyntax"); 200 this.transferSyntaxes = transferSyntaxes; 201 } 202 203 public boolean containsTransferSyntax(String ts) { 204 if ("*".equals(transferSyntaxes[0])) 205 return true; 206 207 for (String s : transferSyntaxes) 208 if (ts.equals(s)) 209 return true; 210 211 return false; 212 } 213 214 public void setQueryOptions(EnumSet<QueryOption> queryOptions) { 215 this.queryOptions = EnumSet.noneOf(QueryOption.class); 216 if (queryOptions != null) 217 this.queryOptions.addAll(queryOptions); 218 } 219 220 public EnumSet<QueryOption> getQueryOptions() { 221 return queryOptions; 222 } 223 224 public void setStorageOptions(StorageOptions storageOptions) { 225 this.storageOptions = storageOptions; 226 } 227 228 public StorageOptions getStorageOptions() { 229 return storageOptions; 230 } 231 232 @Override 233 public String toString() { 234 return promptTo(new StringBuilder(512), "").toString(); 235 } 236 237 public TransferCapability deepCopy() { 238 TransferCapability newTc = new TransferCapability(); 239 240 newTc.setCommonName(getCommonName()); 241 newTc.setQueryOptions(EnumSet.copyOf(getQueryOptions())); 242 newTc.setRole(getRole()); 243 newTc.setStorageOptions(getStorageOptions() == null ? null : getStorageOptions().copy()); 244 newTc.setSopClass(getSopClass()); 245 newTc.setTransferSyntaxes(Arrays.copyOf(getTransferSyntaxes(),getTransferSyntaxes().length)); 246 247 return newTc; 248 } 249 250 public StringBuilder promptTo(StringBuilder sb, String indent) { 251 String indent2 = indent + " "; 252 StringUtils.appendLine(sb, indent, "TransferCapability[cn: ", commonName); 253 StringUtils.appendLine(sb, indent2, "role: ", role); 254 sb.append(indent2).append("as: "); 255 UIDUtils.promptTo(sopClass, sb).append(StringUtils.LINE_SEPARATOR); 256 for (String ts : transferSyntaxes) { 257 sb.append(indent2).append("ts: "); 258 UIDUtils.promptTo(ts, sb).append(StringUtils.LINE_SEPARATOR); 259 } 260 if (queryOptions != null) 261 sb.append(indent2).append("QueryOptions").append(queryOptions) 262 .append(StringUtils.LINE_SEPARATOR); 263 if (storageOptions != null) 264 sb.append(indent2).append(storageOptions) 265 .append(StringUtils.LINE_SEPARATOR); 266 return sb.append(indent).append(']'); 267 } 268 269}