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) 2013
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.audit;
040
041import java.util.List;
042
043import org.dcm4che3.audit.ActiveParticipant;
044import org.dcm4che3.audit.AuditMessage;
045import org.dcm4che3.audit.EventID;
046import org.dcm4che3.audit.EventIdentification;
047import org.dcm4che3.audit.EventTypeCode;
048import org.dcm4che3.audit.RoleIDCode;
049import org.dcm4che3.conf.core.api.ConfigurableClass;
050import org.dcm4che3.conf.core.api.ConfigurableProperty;
051import org.dcm4che3.conf.core.api.LDAP;
052import org.dcm4che3.data.Code;
053
054/**
055 * Specifies criteria for {@link EventIdentification} and optional also for
056 * {@link ActiveParticipant}s of {@link AuditMessage}s which shall be suppressed.
057 *
058 * Only Audit Messages which match all specified criteria will be suppressed.
059 * 
060 * Audit Messages without any {@code ActiveParticipant} will only match an
061 * {@code AuditSuppressCriteria} with does not specify criteria for
062 * {@code ActiveParticipant}s. 
063 * 
064 * Audit Messages with multiple {@code ActiveParticipants} will match if one
065 * of the {@code ActiveParticipants} match all {@code ActiveParticipant}
066 * specific criteria.
067 * 
068 * @author Gunter Zeilinger <gunterze@gmail.com>
069 *
070 */
071@LDAP(objectClasses = "dcmAuditSuppressCriteria")
072@ConfigurableClass
073public class AuditSuppressCriteria {
074
075    @ConfigurableProperty(name="cn")
076    private String commonName;
077
078    @ConfigurableProperty(name="dcmAuditEventID")
079    private EventID[] eventIDs = {};
080
081    @ConfigurableProperty(name="dcmAuditEventTypeCode")
082    private EventTypeCode[] eventTypeCodes = {};
083
084    @ConfigurableProperty(name="dcmAuditEventActionCode")
085    private String eventActionCodes[] = {};
086
087    @ConfigurableProperty(name="dcmAuditEventOutcomeIndicator")
088    private String[] eventOutcomeIndicators = {};
089
090    @ConfigurableProperty(name="dcmAuditUserID")
091    private String[] userIDs = {};
092
093    @ConfigurableProperty(name="dcmAuditAlternativeUserID")
094    private String[] alternativeUserIDs = {};
095
096    @ConfigurableProperty(name="dcmAuditUserRoleIDCode")
097    private RoleIDCode[] roleIDCodes = {};
098
099    @ConfigurableProperty(name="dcmAuditNetworkAccessPointID")
100    private String[] networkAccessPointIDs = {};
101
102    @ConfigurableProperty(name="dcmAuditUserIsRequestor")
103    private Boolean userIsRequestor;
104
105    public AuditSuppressCriteria() {
106    }
107
108    public void setCommonName(String commonName) {
109        this.commonName = commonName;
110    }
111
112    public AuditSuppressCriteria(String cn) {
113        if (cn.isEmpty())
114            throw new IllegalArgumentException("cn must not be empty");
115        this.commonName = cn;
116    }
117
118    public String getCommonName() {
119        return commonName;
120    }
121
122    public EventID[] getEventIDs() {
123        return eventIDs;
124    }
125
126    /** Specifies values of {@link EventID} of the {@link EventIdentification}
127     * of messages which shall be suppressed.
128     * 
129     * If no value is specified, the {@link EventID} of the {@link EventIdentification}
130     * of a message will not be concerned by this {@code AuditSuppressCriteria}.
131     * 
132     * @param eventIDs values of {@code EventID} of the {@code EventIdentification}
133     * of messages which shall be suppressed. 
134     */
135    public void setEventIDs(EventID... eventIDs) {
136        this.eventIDs = eventIDs;
137    }
138
139    public String[] getEventIDsAsStringArray() {
140        return toStringArray(eventIDs);
141    }
142
143    public void setEventIDsAsStringArray(String[] ss) {
144        setEventIDs(toEventIDArray(ss));
145    }
146
147    public EventTypeCode[] getEventTypeCodes() {
148        return eventTypeCodes;
149    }
150
151    /** Specifies values of {@link EventTypeCode} of the {@link EventIdentification}
152     * of messages which shall be suppressed.
153     * 
154     * If no value is specified, the {@link EventTypeCode} of the {@link EventIdentification}
155     * of a message will not be concerned by this {@code AuditSuppressCriteria}.
156     * 
157     * If values are specified, Audit Messages without {@code EventTypeCode}s
158     * will not match this {@code AuditSuppressCriteria}.
159     * 
160     * Audit Messages with multiple {@code EventTypeCode}s will match if one
161     * of the {@code EventTypeCode} match one of the specified values.
162     * 
163     * @param eventTypeCodes values of {@link EventTypeCode} of the {@link EventIdentification}
164     * of messages which shall be suppressed. 
165     */
166    public void setEventTypeCodes(EventTypeCode... eventTypeCodes) {
167        this.eventTypeCodes = eventTypeCodes;
168    }
169
170    public String[] getEventTypeCodesAsStringArray() {
171        return toStringArray(eventTypeCodes);
172    }
173
174    public void setEventTypeCodesAsStringArray(String... ss) {
175        setEventTypeCodes(toEventTypeCodeArray(ss));
176    }
177
178    public String[] getEventActionCodes() {
179        return eventActionCodes;
180    }
181
182    /** Specifies values of {@code EventActionCode} of the {@link EventIdentification}
183     * of messages which shall be suppressed.
184     * 
185     * If no value is specified, the {@code EventActionCode} of the {@link EventIdentification}
186     * of a message will not be concerned by this {@code AuditSuppressCriteria}.
187     * 
188     * If values are specified, Audit Messages without {@code EventActionCode}
189     * will not match this {@code AuditSuppressCriteria}.
190     * 
191     * @param eventActionCodes values of {@code EventActionCode} of the {@link EventIdentification}
192     * of messages which shall be suppressed. 
193     */
194    public void setEventActionCodes(String... eventActionCodes) {
195        this.eventActionCodes = eventActionCodes;
196    }
197
198    public String[] getEventOutcomeIndicators() {
199        return eventOutcomeIndicators;
200    }
201
202    /** Specifies values of {@code EventOutcomeIndicator} of the {@link EventIdentification}
203     * of messages which shall be suppressed.
204     * 
205     * If no value is specified, the {@code EventOutcomeIndicator} of the {@link EventIdentification}
206     * of a message will not be concerned by this {@code AuditSuppressCriteria}.
207     * 
208     * @param eventOutcomeIndicators values of {@code EventOutcomeIndicator} of the {@link EventIdentification}
209     * of messages which shall be suppressed. 
210     */
211    public void setEventOutcomeIndicators(String... eventOutcomeIndicators) {
212        this.eventOutcomeIndicators = eventOutcomeIndicators;
213    }
214
215    public String[] getUserIDs() {
216        return userIDs;
217    }
218
219    /** Specifies values of {@code UserID} of {@link ActiveParticipant}s of
220     * messages which shall be suppressed.
221     * 
222     * If no value is specified, the {@code UserID} of {@link ActiveParticipant}s
223     * of a message will not be concerned by this {@code AuditSuppressCriteria}.
224     * 
225     * @param userIDs values of {@code UserID} of the {@link ActiveParticipant}s
226     * of messages which shall be suppressed. 
227     */
228    public void setUserIDs(String... userIDs) {
229        this.userIDs = userIDs;
230    }
231
232    public String[] getAlternativeUserIDs() {
233        return alternativeUserIDs;
234    }
235
236    /** Specifies values of {@code AlternativeUserID} of {@link ActiveParticipant}s of
237     * messages which shall be suppressed.
238     * 
239     * {@code ActiveParticipant}s with multiple {@code EventTypeCode}s will match if one
240     * of the {@code EventTypeCode} match one of the specified values.
241     *
242     * If no value is specified, the {@code AlternativeUserID} of {@code ActiveParticipant}s
243     * of a message will not be concerned by this {@code AuditSuppressCriteria}.
244     * 
245     * If values are specified,  {@code ActiveParticipant}s without {@code AlternativeUserID}
246     * will not match this {@code AuditSuppressCriteria}.
247     *
248     * @param altUserID values of {@code AlternativeUserID} of the {@link ActiveParticipant}s
249     * of messages which shall be suppressed. 
250     */
251    public void setAlternativeUserIDs(String... altUserID) {
252        this.alternativeUserIDs = altUserID;
253    }
254
255    public RoleIDCode[] getUserRoleIDCodes() {
256        return roleIDCodes;
257    }
258
259    /** Specifies values of {@link RoleIDCode} of {@link ActiveParticipant}s of
260     * messages which shall be suppressed.
261     * 
262     * If no value is specified, the {@code RoleIDCode} of {@link ActiveParticipant}s
263     * of a message will not be concerned by this {@code AuditSuppressCriteria}.
264     * 
265     * If values are specified,  {@code ActiveParticipant}s without {@code RoleIDCode}s
266     * will not match this {@code AuditSuppressCriteria}.
267     *
268     * {@code ActiveParticipant}s with multiple {@code RoleIDCode}s will match if one
269     * of the {@code RoleIDCode} match one of the specified values.
270     * 
271     * @param roleIDCodes values of {@code RoleIDCode} of the {@link ActiveParticipant}s
272     * of messages which shall be suppressed. 
273     */
274    public void setUserRoleIDCodes(RoleIDCode... roleIDCodes) {
275        this.roleIDCodes = roleIDCodes;
276    }
277
278    public String[] getUserRoleIDCodesAsStringArray() {
279        return toStringArray(roleIDCodes);
280    }
281
282    public void setUserRoleIDCodesAsStringArray(String... ss) {
283        setUserRoleIDCodes(toRoleIDCodeArray(ss));
284    }
285
286    public String[] getNetworkAccessPointIDs() {
287        return networkAccessPointIDs;
288    }
289
290    /** Specifies values of {@code NetworkAccessPointID} of {@link ActiveParticipant}s of
291     * messages which shall be suppressed.
292     * 
293     * If no value is specified, the {@code NetworkAccessPointID} of {@link ActiveParticipant}s
294     * of a message will not be concerned by this {@code AuditSuppressCriteria}.
295     * 
296     * If values are specified,  {@code ActiveParticipant}s without {@code NetworkAccessPointID}s
297     * will not match this {@code AuditSuppressCriteria}.
298     *
299     * @param networkAccessPointIDs values of {@code NetworkAccessPointID} of the {@link ActiveParticipant}s
300     * of messages which shall be suppressed. 
301     */
302    public void setNetworkAccessPointIDs(String... networkAccessPointIDs) {
303        this.networkAccessPointIDs = networkAccessPointIDs;
304    }
305
306    public Boolean getUserIsRequestor() {
307        return userIsRequestor;
308    }
309
310    /** Specifies value of {@code UserIsRequestor} of {@link ActiveParticipant}s of
311     * messages which shall be suppressed.
312     * 
313     * If {@code null} is specified, the value of {@code UserIsRequestor} of {@link ActiveParticipant}s
314     * of a message will not be concerned by this {@code AuditSuppressCriteria}.
315     * 
316     * @param userIsRequestor value of {@code UserIsRequestor} of the {@link ActiveParticipant}s
317     * of messages which shall be suppressed or {@code null}. 
318     */
319    public void setUserIsRequestor(Boolean userIsRequestor) {
320        this.userIsRequestor = userIsRequestor;
321    }
322
323    public boolean match(AuditMessage msg) {
324        if (!match(msg.getEventIdentification()))
325            return false;
326
327        if (!match(msg.getActiveParticipant()))
328            return false;
329
330        return true;
331    }
332
333    private boolean match(EventIdentification eventIdentification) {
334        if (!matchEventID(eventIdentification.getEventID()))
335            return false;
336
337        if (!matchEventTypeCodes(eventIdentification.getEventTypeCode()))
338            return false;
339
340        if (!isEmptyOrContains(eventActionCodes,
341                        eventIdentification.getEventActionCode()))
342            return false;
343
344        if (!isEmptyOrContains(eventOutcomeIndicators,
345                        eventIdentification.getEventOutcomeIndicator()))
346            return false;
347
348        return true;
349    }
350
351    private boolean matchEventID(EventID o) {
352        if (eventIDs.length == 0)
353            return true;
354
355        for (EventID eventyID : eventIDs) {
356            if (eventyID.getCode().equals(o.getCode())
357                 && equals(eventyID.getCodeSystemName(), o.getCodeSystemName()))
358                return true;
359        }
360        return false;
361    }
362
363    private boolean equals(Object o1, Object o2) {
364        return o1 != null ? o1.equals(o2) : o2 == null;
365    }
366
367    private boolean matchEventTypeCodes(List<EventTypeCode> list) {
368        if (eventTypeCodes.length == 0)
369            return true;
370
371        for (EventTypeCode o : list) {
372            for (EventTypeCode eventTypeCode : eventTypeCodes) {
373                if (eventTypeCode.getCode().equals(o.getCode())
374                     && equals(eventTypeCode.getCodeSystemName(), o.getCodeSystemName()))
375                    return true;
376            }
377        }
378
379        return false;
380    }
381
382    private boolean match(List<ActiveParticipant> aps) {
383        if (!containsActiveParticipantCriteria())
384            return true;
385
386        for (ActiveParticipant ap : aps) {
387            if (match(ap))
388                return true;
389        }
390        return false;
391    }
392
393    private boolean match(ActiveParticipant ap) {
394        if (!isEmptyOrContains(userIDs, ap.getUserID()))
395            return false;
396
397        if (!isEmptyOrContains(alternativeUserIDs,
398                ap.getAlternativeUserID()))
399            return false;
400
401        if (!isEmptyOrContains(networkAccessPointIDs, 
402                ap.getNetworkAccessPointID()))
403            return false;
404
405        if (!matchRoleIDCodes(ap.getRoleIDCode()))
406            return false;
407
408        return userIsRequestor == null
409                || ap.isUserIsRequestor() == userIsRequestor.booleanValue();
410    }
411
412    private boolean matchRoleIDCodes(List<RoleIDCode> list) {
413        if (roleIDCodes.length == 0)
414            return true;
415
416        for (RoleIDCode o : list) {
417            for (RoleIDCode roleIDCode : roleIDCodes) {
418                if (roleIDCode.getCode().equals(o.getCode())
419                     && equals(roleIDCode.getCodeSystemName(), o.getCodeSystemName()))
420                    return true;
421            }
422        }
423
424        return false;
425    }
426
427    public boolean containsActiveParticipantCriteria() {
428        return userIDs.length == 0
429                && alternativeUserIDs.length == 0
430                && roleIDCodes.length == 0
431                && networkAccessPointIDs.length == 0
432                && userIsRequestor == null;
433    }
434
435    private boolean isEmptyOrContains(String[] ss, String o) {
436        if (ss.length == 0)
437            return true;
438
439        if (o == null)
440            return false;
441
442        for (String s : ss)
443            if (o.equals(s))
444                return true;
445
446        return false;
447    }
448
449    private static String[] toStringArray(EventID... a) {
450        String[] ss = new String[a.length];
451        for (int i = 0; i < a.length; i++) {
452            ss[i] = new Code(
453                    a[i].getCode(),
454                    a[i].getCodeSystemName(),
455                    null, 
456                    a[i].getOriginalText())
457                .toString();
458        }
459        return ss;
460    }
461
462    private static String[] toStringArray(EventTypeCode... a) {
463        String[] ss = new String[a.length];
464        for (int i = 0; i < a.length; i++) {
465            ss[i] = new Code(
466                    a[i].getCode(),
467                    a[i].getCodeSystemName(),
468                    null, 
469                    a[i].getOriginalText())
470                .toString();
471        }
472        return ss;
473    }
474
475    private static String[] toStringArray(RoleIDCode... a) {
476        String[] ss = new String[a.length];
477        for (int i = 0; i < a.length; i++) {
478            ss[i] = new Code(
479                    a[i].getCode(),
480                    a[i].getCodeSystemName(),
481                    null, 
482                    a[i].getOriginalText())
483                .toString();
484        }
485        return ss;
486    }
487
488    private static EventID[] toEventIDArray(String... ss) {
489        EventID[] a = new EventID[ss.length];
490        for (int i = 0; i < ss.length; i++) {
491            Code code = new Code(ss[i]);
492            a[i] = new EventID();
493            a[i].setCode(code.getCodeValue());
494            a[i].setCodeSystemName(code.getCodingSchemeDesignator());
495            a[i].setOriginalText(code.getCodeMeaning());
496        }
497        return a;
498    }
499
500    private static EventTypeCode[] toEventTypeCodeArray(String... ss) {
501        EventTypeCode[] a = new EventTypeCode[ss.length];
502        for (int i = 0; i < ss.length; i++) {
503            Code code = new Code(ss[i]);
504            a[i] = new EventTypeCode();
505            a[i].setCode(code.getCodeValue());
506            a[i].setCodeSystemName(code.getCodingSchemeDesignator());
507            a[i].setOriginalText(code.getCodeMeaning());
508        }
509        return a;
510    }
511
512    private static RoleIDCode[] toRoleIDCodeArray(String... ss) {
513        RoleIDCode[] a = new RoleIDCode[ss.length];
514        for (int i = 0; i < ss.length; i++) {
515            Code code = new Code(ss[i]);
516            a[i] = new RoleIDCode();
517            a[i].setCode(code.getCodeValue());
518            a[i].setCodeSystemName(code.getCodingSchemeDesignator());
519            a[i].setOriginalText(code.getCodeMeaning());
520        }
521        return a;
522    }
523}