/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is part of dcm4che, an implementation of DICOM(TM) in * Java(TM), hosted at https://github.com/gunterze/dcm4che. * * The Initial Developer of the Original Code is * Agfa Healthcare. * Portions created by the Initial Developer are Copyright (C) 2011-2014 * the Initial Developer. All Rights Reserved. * * Contributor(s): * See @authors listed below * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ package org.dcm4chee.archive.noniocm.impl; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import javax.ejb.Stateless; import javax.inject.Inject; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.dcm4che3.conf.api.IApplicationEntityCache; import org.dcm4che3.conf.core.api.ConfigurationException; import org.dcm4che3.data.Attributes; import org.dcm4che3.data.Tag; import org.dcm4che3.data.VR; import org.dcm4che3.net.ApplicationEntity; import org.dcm4che3.net.Device; import org.dcm4chee.archive.entity.history.ActionHistory; import org.dcm4chee.archive.entity.history.ActionHistory.HierarchyLevel; import org.dcm4chee.archive.entity.history.InstanceHistory; import org.dcm4chee.archive.noniocm.NonIOCMChangeRequestorQRService; import org.dcm4chee.archive.query.QueryContext; import org.dcm4chee.archive.store.scu.CStoreSCUContext; /** * @author Franz Willer <franz.willer@gmail.com> */ @Stateless public class NonIOCMChangeRequestorQRServiceEJB implements NonIOCMChangeRequestorQRService { private static final String NON_IOCM_QC_HISTORY = "NON_IOCM_QC_HISTORY"; @PersistenceContext(name="dcm4chee-arc") private EntityManager em; @Inject private IApplicationEntityCache aeCache; @Override public void updateQueryRequestAttributes(Attributes keys, Collection<String> sourceDeviceAETs) { NonIocmQRLevel level = getLevelWithUIDs(keys); if (level != null) updateRequestUIDs(sourceDeviceAETs, level, keys, findHistory(level, true, level.getUids(keys)), false); } @Override public void updateQueryResponseAttributes(QueryContext context, Attributes match) { Device remoteDevice = getRemoteDevice(context); if (remoteDevice != null) { Attributes keys = context.getKeys(); String studyIUID = match.getString(Tag.StudyInstanceUID); NonIocmQRLevel level = keys.getString(Tag.QueryRetrieveLevel) != null ? NonIocmQRLevel.valueOf(keys.getString(Tag.QueryRetrieveLevel)) : getLevelWithUIDs(keys); if (level != null) { @SuppressWarnings("unchecked") HashMap<String, List<InstanceHistory>> historyMap = (HashMap<String, List<InstanceHistory>>) context.getProperty(NON_IOCM_QC_HISTORY); if (historyMap == null) { historyMap = new HashMap<String, List<InstanceHistory>>(); context.setProperty(NON_IOCM_QC_HISTORY, historyMap); } List<InstanceHistory> history = historyMap.get(studyIUID); if(history == null) { history = findHistory(NonIocmQRLevel.STUDY, false, studyIUID); historyMap.put(studyIUID, history); } updateResponseUIDs(remoteDevice.getApplicationAETitles(), level, match, history); } } } @Override public Device getRemoteDevice(QueryContext context) { Device d = context.getRemoteDevice(); if (d == null) { try { ApplicationEntity ae = aeCache.get(context.getRemoteAET()); if (ae != null) d = ae.getDevice(); } catch (ConfigurationException ignore) { } } return d; } @Override public void updateRetrieveRequestAttributes(Attributes keys, Collection<String> sourceDeviceAETs) { NonIocmQRLevel level = getLevelWithUIDs(keys); if (level != null) updateRequestUIDs(sourceDeviceAETs, level, keys, findHistory(level, true, level.getUids(keys)), true); } @Override public void updateRetrieveResponseAttributes(CStoreSCUContext context, Attributes attrs) { String studyIUID = attrs.getString(Tag.StudyInstanceUID); List<InstanceHistory> history = null; @SuppressWarnings("unchecked") HashMap<String, List<InstanceHistory>> historyMap = (HashMap<String, List<InstanceHistory>>) context .getProperty(NON_IOCM_QC_HISTORY); if (historyMap == null) { historyMap = new HashMap<String, List<InstanceHistory>>(); context.setProperty(NON_IOCM_QC_HISTORY, historyMap); } if (historyMap.containsKey(attrs.getString(Tag.StudyInstanceUID))) { history = historyMap.get(studyIUID); } else { history = findHistory(NonIocmQRLevel.STUDY, false, studyIUID); historyMap.put(studyIUID, history); } updateResponseUIDs(context.getRemoteAE().getDevice() .getApplicationAETitles(), NonIocmQRLevel.IMAGE, attrs, history); } private NonIocmQRLevel getLevelWithUIDs(Attributes keys) { NonIocmQRLevel level = NonIocmQRLevel.IMAGE; for (; level != null && level.getUids(keys) == null; level = level .parent()) ; return level; } @SuppressWarnings("unchecked") private List<InstanceHistory> findHistory(NonIocmQRLevel level, boolean oldToNew, String... uids) { Query query = em.createNamedQuery(level.getHistoryQueryName(oldToNew)); query.setParameter("uids", Arrays.asList(uids)); return (List<InstanceHistory>) query.getResultList(); } private void updateRequestUIDs(Collection<String> collection, NonIocmQRLevel qrLevel, Attributes keys, List<InstanceHistory> histories, boolean isRetrieve) { String[] uids = qrLevel.getUids(keys); if (histories != null && histories.size() != 0) { InstanceHistory history = null; for (int i = 0 ; i < uids.length ; i++) { for (InstanceHistory h : histories) { if (qrLevel.getOldUID(h).equals(uids[i])) { String noneIocmSourceAET = h.getSeries().getNoneIOCMSourceAET(); if (noneIocmSourceAET != null && collection.contains(noneIocmSourceAET)) { uids[i] = qrLevel.getNewUID(h); if (history == null) history = h; } } } } if (history != null) { ActionHistory.HierarchyLevel hierarchyLevel = isRetrieve ? HierarchyLevel.PATIENT : history.getSeries().getStudy().getAction().getHierarchyLevel(); switch (qrLevel) { case IMAGE: keys.setString(Tag.SOPInstanceUID, VR.UI, uids); uids = new String[] { NonIocmQRLevel.SERIES.getNewUID(history) }; case SERIES: if (hierarchyLevel == ActionHistory.HierarchyLevel.SERIES || hierarchyLevel == HierarchyLevel.INSTANCE) break; keys.setString(Tag.SeriesInstanceUID, VR.UI, uids); uids = new String[] { NonIocmQRLevel.STUDY.getNewUID(history) }; case STUDY: if (hierarchyLevel == ActionHistory.HierarchyLevel.PATIENT) keys.setString(Tag.StudyInstanceUID, VR.UI, uids); default: break; } } } } private void updateResponseUIDs(Collection<String> remoteAETs, NonIocmQRLevel qrLevel, Attributes match, List<InstanceHistory> history) { InstanceHistory oldest = selectOldestHistory(qrLevel, match, history); if (oldest != null && oldest != null) { String noneIocmSourceAET = oldest.getSeries().getNoneIOCMSourceAET(); if (noneIocmSourceAET != null && remoteAETs.contains(noneIocmSourceAET)) { ActionHistory.HierarchyLevel hierarchyLevel = oldest.getSeries().getStudy().getAction().getHierarchyLevel(); switch (qrLevel) { case IMAGE: match.setString(Tag.SOPInstanceUID, VR.UI, NonIocmQRLevel.IMAGE.getOldUID(oldest)); case SERIES: if (hierarchyLevel == ActionHistory.HierarchyLevel.STUDY || hierarchyLevel == HierarchyLevel.PATIENT) match.setString(Tag.SeriesInstanceUID, VR.UI, NonIocmQRLevel.SERIES.getOldUID(oldest)); case STUDY: if (hierarchyLevel == ActionHistory.HierarchyLevel.PATIENT) match.setString(Tag.StudyInstanceUID, VR.UI, NonIocmQRLevel.STUDY.getOldUID(oldest)); default: break; } } } } private InstanceHistory selectOldestHistory(NonIocmQRLevel level, Attributes match, List<InstanceHistory> history) { if (level.getUids(match) == null) return null; String uid = level.getUids(match)[0]; InstanceHistory result = null; if (history != null && history.size() != 0) { for (InstanceHistory h : history) { if (level.getNewUID(h).equals(uid) && (result == null || result.getPk() > h.getPk())) { result = h; } } } return result; } }