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.conf.api; 040 041import java.io.Serializable; 042import java.util.Arrays; 043 044import org.dcm4che3.conf.core.api.ConfigurableClass; 045import org.dcm4che3.conf.core.api.ConfigurableProperty; 046import org.dcm4che3.conf.core.api.LDAP; 047import org.dcm4che3.net.Dimse; 048import org.dcm4che3.net.TransferCapability.Role; 049import org.dcm4che3.util.StringUtils; 050import org.dcm4che3.util.UIDUtils; 051 052/** 053 * @author Gunter Zeilinger <gunterze@gmail.com> 054 */ 055@LDAP(objectClasses = "dcmAttributeCoercion") 056@ConfigurableClass 057public class AttributeCoercion 058 implements Serializable, Comparable<AttributeCoercion> { 059 060 061 private static final long serialVersionUID = 7799241531490684097L; 062 063 @ConfigurableProperty(name = "cn") 064 private String commonName; 065 066 @LDAP(noContainerNode = true) 067 @ConfigurableProperty(name="condition") 068 private Condition condition; 069 070 @ConfigurableProperty(name = "labeledURI") 071 private String uri; 072 073 public AttributeCoercion() { 074 } 075 076 public AttributeCoercion(String commonName, String[] sopClasses, 077 Dimse dimse, Role role, String[] aeTitles, String[] deviceNames, 078 String uri) { 079 if (commonName == null) 080 throw new NullPointerException("commonName"); 081 if (commonName.isEmpty()) 082 throw new IllegalArgumentException("commonName cannot be empty"); 083 084 this.commonName = commonName; 085 this.condition = new Condition( 086 StringUtils.maskNull(sopClasses), 087 dimse, 088 role, 089 StringUtils.maskNull(aeTitles), 090 StringUtils.maskNull(deviceNames)); 091 this.uri = uri; 092 } 093 094 public Condition getCondition() { 095 return condition; 096 } 097 098 public void setCondition(Condition condition) { 099 this.condition = condition; 100 this.condition.calcWeight(); 101 } 102 103 public String getUri() { 104 return uri; 105 } 106 107 public void setUri(String uri) { 108 this.uri = uri; 109 } 110 111 public String getCommonName() { 112 return commonName; 113 } 114 115 public void setCommonName(String commonName) { 116 this.commonName = commonName; 117 } 118 119 public final String[] getSOPClasses() { 120 return condition.sopClasses; 121 } 122 123 public final Dimse getDIMSE() { 124 return condition.dimse; 125 } 126 127 public final Role getRole() { 128 return condition.role; 129 } 130 131 public final String[] getAETitles() { 132 return condition.aeTitles; 133 } 134 135 public final String getURI() { 136 return uri; 137 } 138 139 public boolean matchesCondition(String sopClass, Dimse dimse, Role role, 140 String aeTitle, String deviceName) { 141 return condition.matches(sopClass, dimse, role, aeTitle, deviceName); 142 } 143 144 @Override 145 public int compareTo(AttributeCoercion o) { 146 return condition.compareTo(o.condition); 147 } 148 149 @Override 150 public String toString() { 151 return promptTo(new StringBuilder(64), "").toString(); 152 } 153 154 public StringBuilder promptTo(StringBuilder sb, String indent) { 155 String indent2 = indent + " "; 156 StringUtils.appendLine(sb, indent, 157 "AttributeCoercion[cn: ", commonName); 158 StringUtils.appendLine(sb, indent2, "dimse: ", condition.dimse); 159 StringUtils.appendLine(sb, indent2, "role: ", condition.role); 160 promptCUIDsTo(sb, indent2, condition.sopClasses); 161 promptAETsTo(sb, indent2, condition.aeTitles); 162 StringUtils.appendLine(sb, indent2, "cuids: ", 163 Arrays.toString(condition.sopClasses)); 164 StringUtils.appendLine(sb, indent2, "aets: ", 165 Arrays.toString(condition.aeTitles)); 166 StringUtils.appendLine(sb, indent2, "devs: ", 167 Arrays.toString(condition.deviceNames)); 168 StringUtils.appendLine(sb, indent2, "uri: ", uri); 169 return sb.append(indent).append(']'); 170 } 171 172 private static void promptCUIDsTo(StringBuilder sb, String indent, 173 String[] cuids) { 174 if (cuids.length == 0) 175 return; 176 sb.append(indent).append("cuids: "); 177 for (String cuid : cuids) 178 UIDUtils.promptTo(cuid, sb).append(','); 179 sb.setLength(sb.length()-1); 180 sb.append(StringUtils.LINE_SEPARATOR); 181 } 182 183 private static void promptAETsTo(StringBuilder sb, String indent, 184 String[] aets) { 185 if (aets.length == 0) 186 return; 187 sb.append(indent).append("aets: "); 188 for (String aet : aets) 189 sb.append(aet).append(','); 190 sb.setLength(sb.length()-1); 191 sb.append(StringUtils.LINE_SEPARATOR); 192 } 193 194 @ConfigurableClass 195 public static class Condition 196 implements Serializable, Comparable<Condition> { 197 198 private static final long serialVersionUID = -8993828886666689060L; 199 200 @ConfigurableProperty(name = "dcmSOPClass") 201 String[] sopClasses; 202 203 @ConfigurableProperty(name = "dcmDIMSE") 204 Dimse dimse; 205 206 @ConfigurableProperty(name = "dicomTransferRole") 207 Role role; 208 209 @ConfigurableProperty(name = "dcmDeviceName") 210 String[] deviceNames; 211 212 @ConfigurableProperty(name = "dcmAETitle") 213 String[] aeTitles; 214 215 int weight; 216 217 public Condition() { 218 } 219 220 public Condition(String[] sopClasses, Dimse dimse, Role role, 221 String[] aeTitles, String[] deviceNames) { 222 if (dimse == null) 223 throw new NullPointerException("dimse"); 224 if (role == null) 225 throw new NullPointerException("role"); 226 227 this.sopClasses = sopClasses; 228 this.dimse = dimse; 229 this.role = role; 230 this.aeTitles = aeTitles; 231 this.deviceNames = deviceNames; 232 calcWeight(); 233 } 234 235 public void calcWeight() { 236 this.weight = (aeTitles.length != 0 ? 4 : 0) 237 + (deviceNames.length != 0 ? 2 : 0) 238 + (sopClasses.length != 0 ? 1 : 0); 239 240 } 241 242 public String[] getSopClasses() { 243 return sopClasses; 244 } 245 246 public void setSopClasses(String... sopClasses) { 247 this.sopClasses = sopClasses; 248 } 249 250 public Dimse getDimse() { 251 return dimse; 252 } 253 254 public void setDimse(Dimse dimse) { 255 this.dimse = dimse; 256 } 257 258 public Role getRole() { 259 return role; 260 } 261 262 public void setRole(Role role) { 263 this.role = role; 264 } 265 266 public String[] getDeviceNames() { 267 return deviceNames; 268 } 269 270 public void setDeviceNames(String... deviceNames) { 271 this.deviceNames = deviceNames; 272 } 273 274 public String[] getAeTitles() { 275 return aeTitles; 276 } 277 278 public void setAeTitles(String... aeTitles) { 279 this.aeTitles = aeTitles; 280 } 281 282 @Override 283 public int compareTo(Condition o) { 284 return o.weight - weight; 285 } 286 287 public boolean matches(String sopClass, Dimse dimse, Role role, 288 String aeTitle, String deviceName) { 289 return this.dimse == dimse 290 && this.role == role 291 && isEmptyOrContains(this.deviceNames, deviceName) 292 && isEmptyOrContains(this.aeTitles, aeTitle) 293 && isEmptyOrContains(this.sopClasses, sopClass); 294 } 295 296 private static boolean isEmptyOrContains(Object[] a, Object o) { 297 if (o == null || a.length == 0) 298 return true; 299 300 for (int i = 0; i < a.length; i++) 301 if (o.equals(a[i])) 302 return true; 303 304 return false; 305 } 306 307 } 308 309}