Commits

Tim Olsen committed dc7d2c9

Modifications to support DICOM DIR. This builds a ZIP based on comma-delited scan IDs or TYPEs. I also refactored some of the related code. There is more to refactor there, but its a first step.

  • Participants
  • Parent commits 5c87a25

Comments (0)

Files changed (7)

File plugin-resources/webapp/xnat/java/org/nrg/xdat/om/base/BaseXnatImagescandata.java

 import java.util.Comparator;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.List;
 
 import org.nrg.xdat.bean.CatCatalogBean;
 import org.nrg.xdat.bean.CatEntryBean;
 import org.nrg.xdat.om.XnatResourceseries;
 import org.nrg.xdat.om.base.auto.AutoXnatImagescandata;
 import org.nrg.xft.ItemI;
+import org.nrg.xft.search.CriteriaCollection;
 import org.nrg.xft.security.UserI;
 import org.nrg.xft.utils.FileUtils;
+import org.nrg.xft.utils.StringUtils;
 import org.nrg.xnat.exceptions.InvalidArchiveStructure;
 
 /**
 			FileUtils.ValidateUriAgainstRoot(uri,expectedPath,"URI references data outside of the project:" + uri);
 		}
 	}
+	
+	
+	public static List<XnatImagescandata> getScansByIdORType(final String scanID,
+			final XnatImagesessiondata session,UserI user, boolean preLoad) {
+		final CriteriaCollection cc = new CriteriaCollection("OR");
+		CriteriaCollection subcc = new CriteriaCollection("AND");
+		subcc.addClause("xnat:imageScanData/image_session_ID", session.getId());
+		if (scanID.equals("*") || scanID.equals("ALL")) {
+
+		} else if (!scanID.contains(",")) {
+			subcc.addClause("xnat:imageScanData/ID", scanID);
+		} else {
+			final CriteriaCollection subsubcc = new CriteriaCollection("OR");
+			for (final String s : StringUtils.CommaDelimitedStringToArrayList(
+					scanID, true)) {
+				subsubcc.addClause("xnat:imageScanData/ID", s);
+			}
+			subcc.add(subsubcc);
+		}
+		cc.add(subcc);
+
+		subcc = new CriteriaCollection("AND");
+		subcc.addClause("xnat:imageScanData/image_session_ID", session.getId());
+		if (scanID.equals("*") || scanID.equals("ALL")) {
+
+		} else if (scanID.indexOf(",") == -1) {
+			if (scanID.equals("NULL")) {
+				CriteriaCollection subsubcc = new CriteriaCollection("OR");
+				subsubcc.addClause("xnat:imageScanData/type", "", " IS NULL ",
+						true);
+				subsubcc.addClause("xnat:imageScanData/type", "");
+				subcc.add(subsubcc);
+			} else {
+				subcc.addClause("xnat:imageScanData/type", scanID);
+			}
+		} else {
+			CriteriaCollection subsubcc = new CriteriaCollection("OR");
+			for (String s : StringUtils.CommaDelimitedStringToArrayList(scanID,
+					true)) {
+				if (s.equals("NULL")) {
+					subsubcc.addClause("xnat:imageScanData/type", "",
+							" IS NULL ", true);
+					subsubcc.addClause("xnat:imageScanData/type", "");
+				} else {
+					subsubcc.addClause("xnat:imageScanData/type", s);
+				}
+			}
+			subcc.add(subsubcc);
+		}
+		cc.add(subcc);
+
+		return XnatImagescandata.getXnatImagescandatasByField(cc, user,
+				preLoad);
+	}
 }

File plugin-resources/webapp/xnat/java/org/nrg/xnat/restlet/XNATApplication.java

 import org.nrg.xnat.restlet.resources.ProtocolResource;
 import org.nrg.xnat.restlet.resources.ReconList;
 import org.nrg.xnat.restlet.resources.ReconResource;
+import org.nrg.xnat.restlet.resources.ScanDIRResource;
 import org.nrg.xnat.restlet.resources.ScanList;
 import org.nrg.xnat.restlet.resources.ScanResource;
 import org.nrg.xnat.restlet.resources.ScanTypeListing;
         router.attach("/projects/{PROJECT_ID}/subjects/{SUBJECT_ID}/experiments/{ASSESSED_ID}/assessors/{EXPT_ID}",ExptAssessmentResource.class);
         router.attach("/projects/{PROJECT_ID}/subjects/{SUBJECT_ID}/experiments/{ASSESSED_ID}/scans",ScanList.class);
         router.attach("/projects/{PROJECT_ID}/subjects/{SUBJECT_ID}/experiments/{ASSESSED_ID}/scans/{SCAN_ID}",ScanResource.class);
+        router.attach("/projects/{PROJECT_ID}/subjects/{SUBJECT_ID}/experiments/{ASSESSED_ID}/scans/{SCAN_ID}/DICOMDIR",ScanDIRResource.class);
         router.attach("/projects/{PROJECT_ID}/subjects/{SUBJECT_ID}/experiments/{ASSESSED_ID}/reconstructions",ReconList.class);
         router.attach("/projects/{PROJECT_ID}/subjects/{SUBJECT_ID}/experiments/{ASSESSED_ID}/reconstructions/{RECON_ID}",ReconResource.class);
         router.attach("/projects/{PROJECT_ID}/accessibility",ProjectAccessibilityResource.class);
         router.attach("/experiments/{EXPT_ID}",ExperimentResource.class);
         router.attach("/experiments/{ASSESSED_ID}/scans",ScanList.class);
         router.attach("/experiments/{ASSESSED_ID}/scans/{SCAN_ID}",ScanResource.class);
+        router.attach("/experiments/{ASSESSED_ID}/scans/{SCAN_ID}/DICOMDIR",ScanDIRResource.class);
         router.attach("/experiments/{ASSESSED_ID}/reconstructions",ReconList.class);
         router.attach("/experiments/{ASSESSED_ID}/reconstructions/{RECON_ID}",ReconResource.class);
 		router.attach("/experiments/{ASSESSED_ID}/assessors",ProjSubExptAsstList.class);

File plugin-resources/webapp/xnat/java/org/nrg/xnat/restlet/files/utils/RestFileUtils.java

+package org.nrg.xnat.restlet.files.utils;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.lang.StringUtils;
+import org.nrg.xdat.om.XnatExperimentdata;
+import org.nrg.xdat.om.XnatImagescandata;
+import org.nrg.xdat.om.XnatProjectdata;
+import org.nrg.xdat.om.XnatReconstructedimagedata;
+import org.nrg.xdat.om.XnatSubjectdata;
+
+public class RestFileUtils {
+
+	public static String getRelativePath(String p,Map<String,String> _tokens){
+		int i=-1;
+		String _token=null;
+		
+		for(Map.Entry<String,String> token:_tokens.entrySet()){
+			_token=token.getKey();
+			i=p.indexOf('/'+ _token + '/');
+			if(i==-1){
+				i=p.indexOf('/'+ _token);
+				
+				if(i==-1){
+					i=p.indexOf(_token+'/');
+					if(i>-1){
+						i=(p.substring(0, i)).lastIndexOf('/') +1;
+						break;
+					}
+				}else{
+					i++;
+					break;
+				}
+			}else{
+				i++;
+				break;
+			}
+		}
+		
+		if(i==-1){
+			if(p.indexOf(":")>-1){
+				p=p.substring(p.indexOf(":"));
+				p=p.substring(p.indexOf("/"));
+				p=_token+p;
+			}else{
+				p=_token+p;
+			}
+		}else{
+			p=p.substring(i);
+		}
+		
+		for(Map.Entry<String,String> entry:_tokens.entrySet()){
+			p=StringUtils.replace(p, entry.getKey(), entry.getValue());
+		}
+		
+		return p;
+	}
+
+	public static String replaceResourceLabel(String path,Object id,String label){
+		if(StringUtils.isEmpty(label) || id==null){
+			return path;
+		}else{
+			int i=path.indexOf('/'+id.toString() +"/files/");
+			if(i>-1){
+				return StringUtils.replace(path, '/'+id.toString() +"/files/", '/'+label +"/files/");
+			}else{
+				return path;
+			}
+		}
+	}
+
+	public static String replaceInPath(String path,Object id,String newValue){
+		if(StringUtils.isEmpty(newValue) || id==null){
+			return path;
+		}else{
+			int i=path.indexOf('/'+id.toString() +'/');
+			if(i>-1){
+				return StringUtils.replace(path, '/'+id.toString() +'/', '/'+newValue +'/');
+			}else{
+				return path;
+			}
+		}
+	}
+
+	public static Map<String,String> getReMaps(List<XnatImagescandata> scans, List<XnatReconstructedimagedata> recons){
+		final Map<String,String> valuesToReplaceInPath=new Hashtable<String,String>();
+		
+		if(scans!=null){
+			for(final XnatImagescandata scan:scans){
+				if(!StringUtils.isEmpty(scan.getType())){
+					valuesToReplaceInPath.put(scan.getId(), scan.getId()+'-' + scan.getType().replaceAll( "\\W", "_").replaceAll(" ", "_"));
+				}
+			}
+		}
+		
+		if(recons!=null){
+			for(final XnatReconstructedimagedata scan:recons){
+				if(!StringUtils.isEmpty(scan.getType())){
+					valuesToReplaceInPath.put(scan.getId(), scan.getId()+'-' + scan.getType().replaceAll( "\\W", "_").replaceAll(" ", "_"));
+				}
+			}
+		}
+		
+		return valuesToReplaceInPath;
+	}
+	
+	public static String buildRelativePath(String uri,Map<String,String> session_mapping, Map<String,String> valuesToReplace, Object resourceID, String resourceLabel){
+		String relative = RestFileUtils.getRelativePath(uri.replace('\\', '/'), session_mapping);
+        
+        relative=RestFileUtils.replaceResourceLabel(relative, resourceID, resourceLabel);
+        
+        for(Map.Entry<String, String> e:valuesToReplace.entrySet()){
+            relative=RestFileUtils.replaceInPath(relative, e.getKey(), e.getValue());
+        }
+        
+        return relative;
+	}
+	
+	public static Map<String,String> getSessionMaps(List<XnatExperimentdata> assesseds,List<XnatExperimentdata> expts,XnatSubjectdata sub, XnatProjectdata proj){
+		Map<String,String> session_ids=new Hashtable<String,String>();
+		if(assesseds.size()>0){
+			for(XnatExperimentdata session:assesseds){
+				session_ids.put(session.getId(),session.getArchiveDirectoryName());
+			}
+		}else if(expts.size()>0){
+			for(XnatExperimentdata session:expts){
+				session_ids.put(session.getId(),session.getArchiveDirectoryName());
+			}
+		}else if(sub!=null){
+			session_ids.put(sub.getId(),sub.getArchiveDirectoryName());
+		}else if(proj!=null){
+			session_ids.put(proj.getId(),proj.getId());
+		}
+		
+		return session_ids;
+	}
+
+}

File plugin-resources/webapp/xnat/java/org/nrg/xnat/restlet/representations/ZipRepresentation.java

 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
 
 import org.nrg.xft.utils.zip.TarUtils;
 	}
 	
 	public void addEntry(String p, File f){
-		_entries.add(new ZipEntry(p,f));
+		_entries.add(new ZipFileEntry(p,f));
+	}
+	
+	public void addEntry(String p, InputStream is){
+		_entries.add(new ZipStreamEntry(p,is));
 	}
 	
 	public void addEntry(File f){
 				p=_token+p;
 			}
 			
-			_entries.add(new ZipEntry(p,f));
+			_entries.add(new ZipFileEntry(p,f));
 		}else{
 			
-			_entries.add(new ZipEntry(p.substring(i),f));
+			_entries.add(new ZipFileEntry(p.substring(i),f));
 		}
 	}
 	
             this.setDownloadable(true);
         }
             
-        for(ZipEntry ze: this._entries)
+        for(final ZipEntry ze: this._entries)
         {
-              if (!ze.getF().isDirectory())
-              {
-                  zip.write(ze.getPath(),ze.getF());
-              }
+        	if(ze instanceof ZipFileEntry){
+                if (!((ZipFileEntry)ze).getF().isDirectory())
+                {
+                    zip.write(ze.getPath(),((ZipFileEntry)ze).getF());
+                }
+        	}else{
+                zip.write(ze.getPath(),((ZipStreamEntry)ze).getInputStream());
+        	}
         }
               
         // Complete the ZIP file
         zip.close();
 	}
 
+	public abstract class ZipEntry{
+		String path=null;
+		
+		public String getPath() {
+			return path;
+		}
+		public void setPath(String path) {
+			this.path = path;
+		}
+	}
     
-	public class ZipEntry {
-		public ZipEntry(String p,File f){
+	public class ZipFileEntry extends ZipEntry {
+		public ZipFileEntry(String p,File f){
 			path=p;
 			file=f;
 		}
 		
-		String path=null;
 		File file=null;
 		
 		public File getF() {
 		public void setF(File f) {
 			this.file = f;
 		}
-		public String getPath() {
-			return path;
-		}
-		public void setPath(String path) {
-			this.path = path;
+	}
+
+    
+	public class ZipStreamEntry extends ZipEntry {
+		public ZipStreamEntry(String p,InputStream _is){
+			path=p;
+			is=_is;
 		}
 		
+		private InputStream is=null;
 		
+		public InputStream getInputStream() {
+			return is;
+		}
+		public void setInputStream(InputStream _is) {
+			this.is = _is;
+		}
 	}
 }
 

File plugin-resources/webapp/xnat/java/org/nrg/xnat/restlet/resources/ScanDIRResource.java

+package org.nrg.xnat.restlet.resources;
+
+import java.io.File;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.nrg.xdat.om.XnatAbstractresource;
+import org.nrg.xdat.om.XnatImagescandata;
+import org.nrg.xdat.om.XnatImagesessiondata;
+import org.nrg.xft.search.CriteriaCollection;
+import org.nrg.xft.utils.StringUtils;
+import org.nrg.xnat.exceptions.InvalidArchiveStructure;
+import org.nrg.xnat.restlet.files.utils.RestFileUtils;
+import org.nrg.xnat.restlet.representations.ZipRepresentation;
+import org.restlet.Context;
+import org.restlet.data.MediaType;
+import org.restlet.data.Request;
+import org.restlet.data.Response;
+import org.restlet.data.Status;
+import org.restlet.resource.Representation;
+import org.restlet.resource.Variant;
+
+public class ScanDIRResource extends ScanResource {
+
+	public ScanDIRResource(Context context, Request request, Response response) {
+		super(context, request, response);
+		
+		this.getVariants().clear();
+		this.getVariants().add(new Variant(MediaType.APPLICATION_ZIP));
+	}
+	
+
+	@Override
+	public boolean allowPut() {
+		return false;
+	}
+
+	@Override
+	public Representation getRepresentation(Variant variant) {
+		List<XnatImagescandata> scans = new ArrayList<XnatImagescandata>();
+
+		if (scan == null && scanID != null) {
+			if (scan == null && this.session != null) {
+				scanID = URLDecoder.decode(scanID);
+				scans=XnatImagescandata.getScansByIdORType(scanID, session,user,completeDocument);
+			} else {
+				if (this.session == null) {
+					this.getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND,
+							"Unable to find the specified session.");
+					return null;
+				}
+			}
+		}
+		
+		if(scans.size()==0){
+			this.getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND,
+			"Unable to find the specified scan(s).");
+			return null;
+		}
+		
+		ZipRepresentation rep;
+		try {
+			//prepare Maps for use in cleaning file paths and relativing them.
+			final Map<String,String> session_mapping=new Hashtable<String,String>();
+			session_mapping.put(session.getId(),session.getArchiveDirectoryName());
+			session_mapping.put(session.getArchiveDirectoryName(),session.getArchiveDirectoryName());
+			
+			final ArrayList<String> session_ids=new ArrayList<String>();
+			session_ids.add(session.getArchiveDirectoryName());
+			
+			Map<String,String> valuesToReplace=RestFileUtils.getReMaps(scans,null);
+
+			rep = new ZipRepresentation(MediaType.APPLICATION_ZIP,session_ids);
+						
+			//this is the expected path to the SESSION_DIR
+			final String rootPath=session.getArchivePath();
+			
+			//DEECH:probably should have something to store DICOM DIR in right here
+			//DEECH:(probably File.createTempFile...)
+			
+			//iterate through scans and only include DICOM files.
+			for(final XnatImagescandata scan: scans){
+				for(final XnatAbstractresource res: scan.getFile()){
+					if(res.getLabel()!=null && res.getLabel().equals("DICOM")){
+						for(final File f:res.getCorrespondingFiles(rootPath)){
+							final String uri=f.getAbsolutePath();
+			                
+							final String relative = RestFileUtils.buildRelativePath(uri, session_mapping, valuesToReplace, res.getXnatAbstractresourceId(), res.getLabel());
+			                
+							if(f!=null && f.exists()){
+								//DEECH:insert code here. to add records to your stream/file
+								rep.addEntry(relative, f);
+							} 
+						}
+					}
+				}
+			}
+			
+			//DEECH:then output the contents here
+			//either rep.addEntry("DICOMDIR",dicomDIRFile); or rep.addEntry("DICOMDIR",is);
+
+			
+			this.setContentDisposition(String.format("attachment; filename=\"%s\";",rep.getDownloadName()));
+		} catch (Throwable e) {
+			logger.error("", e);
+			this.getResponse().setStatus(Status.SERVER_ERROR_INTERNAL,e.getMessage());
+			return null;
+		}
+
+		
+		return rep;
+	}
+}

File plugin-resources/webapp/xnat/java/org/nrg/xnat/restlet/resources/ScanList.java

 				e.printStackTrace();
 				getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
 				return null;
-				}
+			}
 
 			MediaType mt = overrideVariant(variant);
 			Hashtable<String, Object> params = new Hashtable<String, Object>();

File plugin-resources/webapp/xnat/java/org/nrg/xnat/restlet/resources/files/FileList.java

 import java.util.zip.ZipFile;
 
 import org.apache.commons.fileupload.FileItem;
-import org.apache.commons.lang.StringUtils;
 import org.nrg.xdat.base.BaseElement;
 import org.nrg.xdat.bean.CatCatalogBean;
 import org.nrg.xdat.bean.CatEntryBean;
 import org.nrg.xdat.bean.CatEntryMetafieldBean;
 import org.nrg.xdat.om.XnatAbstractresource;
 import org.nrg.xdat.om.XnatExperimentdata;
-import org.nrg.xdat.om.XnatImagescandata;
-import org.nrg.xdat.om.XnatReconstructedimagedata;
 import org.nrg.xdat.om.XnatResource;
 import org.nrg.xdat.om.XnatResourcecatalog;
 import org.nrg.xdat.turbine.utils.TurbineUtils;
 import org.nrg.xft.XFTTable;
 import org.nrg.xft.exception.ElementNotFoundException;
 import org.nrg.xft.utils.FileUtils;
+import org.nrg.xnat.restlet.files.utils.RestFileUtils;
 import org.nrg.xnat.restlet.representations.CatalogRepresentation;
 import org.nrg.xnat.restlet.representations.ZipRepresentation;
 import org.nrg.xnat.restlet.resources.SecureResource;
 		}
 	}
 	
-	private String getRelativePath(String p,Map<String,String> _tokens){
-		int i=-1;
-		String _token=null;
-		
-		for(Map.Entry<String,String> token:_tokens.entrySet()){
-			_token=token.getKey();
-			i=p.indexOf('/'+ _token + '/');
-			if(i==-1){
-				i=p.indexOf('/'+ _token);
-				
-				if(i==-1){
-					i=p.indexOf(_token+'/');
-					if(i>-1){
-						i=(p.substring(0, i)).lastIndexOf('/') +1;
-						break;
-					}
-				}else{
-					i++;
-					break;
-				}
-			}else{
-				i++;
-				break;
-			}
-		}
-		
-		if(i==-1){
-			if(p.indexOf(":")>-1){
-				p=p.substring(p.indexOf(":"));
-				p=p.substring(p.indexOf("/"));
-				p=_token+p;
-			}else{
-				p=_token+p;
-			}
-		}else{
-			p=p.substring(i);
-		}
-		
-		for(Map.Entry<String,String> entry:_tokens.entrySet()){
-			p=StringUtils.replace(p, entry.getKey(), entry.getValue());
-		}
-		
-		return p;
-	}
-	
-	private String replaceResourceLabel(String path,Object id,String label){
-		if(StringUtils.isEmpty(label) || id==null){
-			return path;
-		}else{
-			int i=path.indexOf('/'+id.toString() +"/files/");
-			if(i>-1){
-				return StringUtils.replace(path, '/'+id.toString() +"/files/", '/'+label +"/files/");
-			}else{
-				return path;
-			}
-		}
-	}
-	
-	private String replaceInPath(String path,Object id,String newValue){
-		if(StringUtils.isEmpty(newValue) || id==null){
-			return path;
-		}else{
-			int i=path.indexOf('/'+id.toString() +'/');
-			if(i>-1){
-				return StringUtils.replace(path, '/'+id.toString() +'/', '/'+newValue +'/');
-			}else{
-				return path;
-			}
-		}
-	}
-	
 	private Map<String,String> getReMaps(){
-		final Map<String,String> valuesToReplaceInPath=new Hashtable<String,String>();
-		
-		if(scans!=null){
-			for(final XnatImagescandata scan:scans){
-				if(!StringUtils.isEmpty(scan.getType())){
-					valuesToReplaceInPath.put(scan.getId(), scan.getId()+'-' + scan.getType().replaceAll( "\\W", "_").replaceAll(" ", "_"));
-				}
-			}
-		}
-		
-		if(recons!=null){
-			for(final XnatReconstructedimagedata scan:recons){
-				if(!StringUtils.isEmpty(scan.getType())){
-					valuesToReplaceInPath.put(scan.getId(), scan.getId()+'-' + scan.getType().replaceAll( "\\W", "_").replaceAll(" ", "_"));
-				}
-			}
-		}
-		
-		return valuesToReplaceInPath;
+		return RestFileUtils.getReMaps(scans,recons);
 	}
 	
 	public Representation representTable(XFTTable table, MediaType mt,Hashtable<String,Object> params,Map<String,Map<String,String>> cp,Map<String,String> session_mapping){
 				CatEntryBean entry = new CatEntryBean();
                 
 				String uri=(String)row[uriIndex];
-                String relative = this.getRelativePath(uri, session_mapping);
+                String relative = RestFileUtils.getRelativePath(uri, session_mapping);
                 
                 entry.setUri(server+uri);
                 
                 relative = relative.replace('\\', '/');
                 
-                relative=this.replaceResourceLabel(relative, row[cat_IDIndex], (String)row[collectionIndex]);
+                relative=RestFileUtils.replaceResourceLabel(relative, row[cat_IDIndex], (String)row[collectionIndex]);
                 
                 for(Map.Entry<String, String> e:valuesToReplace.entrySet()){
-                    relative=this.replaceInPath(relative, e.getKey(), e.getValue());
+                    relative=RestFileUtils.replaceInPath(relative, e.getKey(), e.getValue());
                 }
                 
                 entry.setCachepath(relative);
 			
 			for(final Object[] row:table.rows()){	
 				final String uri=(String)row[uriIndex];
-                String relative = this.getRelativePath(uri, session_mapping);
-                
-                relative = relative.replace('\\', '/');
-                                
-                relative=this.replaceResourceLabel(relative, row[cat_IDIndex], (String)row[collectionIndex]);
-                
-                for(Map.Entry<String, String> e:valuesToReplace.entrySet()){
-                    relative=this.replaceInPath(relative, e.getKey(), e.getValue());
-                }
+                String relative = RestFileUtils.buildRelativePath(uri, session_mapping, valuesToReplace, row[cat_IDIndex], (String)row[collectionIndex]);
                 
 				final File child=(File)row[fileIndex];
 				if(child!=null && child.exists())