Commits

Tim Olsen committed a5e88ec Merge

Merge changes from mohanar

Comments (0)

Files changed (36)

plugin-resources/project-skeletons/xnat/src/schemas/xnat/xnat.xsd

 					</xs:element>
 					<xs:element name="educationDesc" type="xs:string" minOccurs="0"/>
 					<xs:element name="race" type="xs:string" minOccurs="0"/>
+					<xs:element name="race2" type="xs:string" minOccurs="0"/>
+					<xs:element name="race3" type="xs:string" minOccurs="0"/>
+					<xs:element name="race4" type="xs:string" minOccurs="0"/>
+					<xs:element name="race5" type="xs:string" minOccurs="0"/>
+					<xs:element name="race6" type="xs:string" minOccurs="0"/>
 					<xs:element name="ethnicity" type="xs:string" minOccurs="0"/>
 					<xs:element name="weight" minOccurs="0">
 						<xs:complexType>
 					<xs:element name="start_time_injection" type="xs:dateTime" minOccurs="0"/>
 					<xs:element name="blood_glucose" type="xs:float" minOccurs="0"/>
 					<xs:element name="blood_glucose_units" type="xs:string" minOccurs="0"/>
+					<xs:element name="blood_glucose_collection_time" type="xs:dateTime" minOccurs="0"/>
 				</xs:sequence>
 			</xs:extension>
 		</xs:complexContent>

plugin-resources/repository/dcm/jars/DicomUtils-1.0.jar

Binary file modified.

plugin-resources/repository/xdat/jars/xdat-1.jar

Binary file modified.

plugin-resources/webapp/xdat-templates/macros/TurbineMacros.vm

 	#end
 #end
 
+#macro (xdatBooleanRadioYesNoWithoutDefault $name $item $vr)
+#if ($vr)
+	#if($vr.getField($name))
+		<font color="red">&#8658</font>
+	#end
+#end
+	#set($value = $!item.getBooleanProperty($name))
+
+	#if ($value == true)
+	<input type="radio" name="$name" value="1" CHECKED/>&nbsp;yes
+	<input type="radio" name="$name" value="0"/>&nbsp;no
+	#elseif ($value == false)
+	<input type="radio" name="$name" value="1"/>&nbsp;yes
+	<input type="radio" name="$name" value="0" CHECKED/>&nbsp;no
+	#else
+	<input type="radio" name="$name" value="1"/>&nbsp;yes
+	<input type="radio" name="$name" value="0"/>&nbsp;no
+	#end
+#end
+
+#macro (xdatRadioButtonGroup $name $item $possibleValues $vr)
+#if ($vr)
+	#if($vr.getField($name))
+		<font color="red">&#8658</font>
+	#end
+#end
+	#if($item.isPKField($name) && (!$vr.getField($name)))
+		<input ID="$name" type="hidden" name="$name" value="$item.getProperty($name)"/>
+		$item.getProperty($name)
+	#else
+		#if ($possibleValues.size()==0)
+			<input ID="$name" type="text" name="$name" value="$item.getProperty($name)"/>
+		#else
+			#foreach ($pValue in $possibleValues)
+			<input type="radio" name="$name" VALUE="$pValue" #if($pValue.equals($item.getProperty($name))) CHECKED #end />&nbsp;$pValue
+			#end
+		#end
+	#end
+#end
 
 #macro (xdatComboBox $name $item $settings_alias $vr)
  #if ($vr)
 	#end
 #end
 
+#macro (xdatSimpleSelectBox $name $item $possibleValues $vr)
+#if ($vr)
+	#if($vr.getField($name))
+		<font color="red">&#8658</font>
+	#end
+#end
+	#if($item.isPKField($name) && (!$vr.getField($name)))
+		<input ID="$name" type="hidden" name="$name" value="$item.getProperty($name)"/>
+		$item.getProperty($name)
+	#else
+		#if ($possibleValues.size()==0)
+			<input ID="$name" type="text" name="$name" value="$item.getProperty($name)"/>
+		#else
+			<SELECT ID="$name" name="$name">
+				<OPTION VALUE="">(SELECT)</OPTION>
+				#foreach ($pValue in $possibleValues)
+				<OPTION VALUE="$pValue" #if($pValue.equals($item.getProperty($name))) SELECTED #end>$pValue</OPTION>
+				#end
+			</SELECT>
+		#end
+	#end
+#end
+
 #macro (xdatDateBox $name $item $vr $years)
  #if ($vr)
 	  #if($vr.getField($name))
  <!-- no object found -->
  #end
 #end
+
+#macro(escapeHTML $s)
+$!turbineUtils.escapeHTML($s)
+#end
+ 
+#macro(escapeJS $s)
+$!turbineUtils.escapeJS($s)
+#end

plugin-resources/webapp/xdat-templates/screens/Login.vm

         <font face="$ui.sansSerifFonts">
         #foreach($key in $data.getParameters().getKeys())
         	#if ($key!="action" && $key!="template" &&$key!="password" &&$key!="username" &&$key!="exception")
-        	<input type="hidden" name="$key" value="$turbineUtils.escapeHTML($data.getParameters().getString($key))">	
+        	<input type="hidden" name="$key" value="$!turbineUtils.escapeHTML($!data.getParameters().getString($key))">		
         	#end
         #end
           <input type="submit" value="Login">

plugin-resources/webapp/xdat-templates/screens/Register.vm

 <form name="form2" id="registerForm" method="post" action="$link.setAction("XDATRegisterUser")" onSubmit="return XNAT.app.register.validateForm();">
 		#foreach($key in $data.getParameters().getKeys())
         	#if ($key!="action" && $key!="template" &&$key!="password" &&$key!="phone" &&$key!="comments" &&!$key.startsWith("xdat:user") &&$key!="username" &&$key!="exception")
-   		<input type="hidden" name="$key" value="$turbineUtils.escapeHTML($data.getParameters().getString($key))">	
+   		<input type="hidden" name="$key" value="$!turbineUtils.escapeHTML($!data.getParameters().getString($key))">	
         	#end
         #end
   <table valign="top" align="center">

plugin-resources/webapp/xnat-templates/screens/ConfirmRegistration.vm

   </table>
         #foreach($key in $data.getParameters().getKeys())
         	#if ($key!="action" && $key!="template" &&$key!="password" &&!$key.startsWith("xdat:user") &&$key!="username" &&$key!="exception")
-        		<input type="hidden" name="$key" value="$turbineUtils.escapeHTML($data.getParameters().getString($key))">	
+        		<input type="hidden" name="$key" value="$!turbineUtils.escapeHTML($!data.getParameters().getString($key))">	
         	#end
         #end
 </form>

plugin-resources/webapp/xnat-templates/screens/DICOMUploadApplet.vm

+<script type="text/javascript" src="$content.getURI("scripts/java/deployJava.js")"></script>
+<script type="text/javascript">
+// The upload applet requires at least Java 1.5 (because of the wizard library).
+// We use Java's deployJava.js (http://java.sun.com/javase/6/docs/technotes/guides/jweb/deployment_advice.html)
+// to ensure that a supported version of the JRE exists on the client.
+// Use an anonymous function to prevent global scope
+(function() {
+    SUPPORTED_JRE_VERSIONS = ["1.5", "1.6", "1.7"];
+    
+    function hasSupport(versions) {
+        for (var i=0; i < versions.length; i++) {
+            if (deployJava.versionCheck(versions[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    if (!hasSupport(SUPPORTED_JRE_VERSIONS)) {
+        alert("Applet will not work without supported JRE version.  Requires one of " + SUPPORTED_JRE_VERSIONS.join(", "));
+    }
+})();
+</script>
+
 <APPLET CODE="org.nrg.upload.ui.UploadAssistantApplet"
   CODEBASE="$content.getURI("applet/")"
   ARCHIVE="UploadAssistant-0.1-SNAPSHOT.jar,wizard-0.998.2-SNAPSHOT.jar,json-20080701.jar,DicomUtils-1.0.jar,DicomEdit-1.2-SNAPSHOT.jar,dcm4che-core-2.0.22-SNAPSHOT.jar,dcm4che-net-2.0.22-SNAPSHOT.jar,log4j-1.2.15.jar,slf4j-api-1.5.2.jar,slf4j-log4j12-1.5.2.jar,antlr-runtime-3.2.jar,stringtemplate-3.2.jar,ecat-io-0.1-SNAPSHOT.jar,ecat-edit-0.1-SNAPSHOT.jar"

plugin-resources/webapp/xnat-templates/screens/ForgotLogin.vm

   </table>
         #foreach($key in $data.getParameters().getKeys())
         	#if ($key!="action" && $key!="template" &&$key!="password" &&!$key.startsWith("xdat:user") &&$key!="username" &&$key!="exception")
-        	<input type="hidden" name="$key" value="$turbineUtils.escapeHTML($data.getParameters().getString($key))">	
+        	<input type="hidden" name="$key" value="$!turbineUtils.escapeHTML($!data.getParameters().getString($key))">	
         	#end
         #end
 </form>

plugin-resources/webapp/xnat-templates/screens/login_box.vm

       <td align ="left">
         <font face="$ui.sansSerifFonts">
         #foreach($key in $data.getParameters().getKeys())
-        	#if ($key!="action" && $key!="template" &&$key!="password" &&!$key.startsWith("xdat:user") &&$key!="username" &&$key!="exception" &&$key!="username" &&$key!="exception")
-        		<input type="hidden" name="$key" value="$turbineUtils.escapeHTML($data.getParameters().getString($key))">	
-        	#end
+          	#if ($key!="action" && $key!="template" &&$key!="password" &&!$key.startsWith("xdat:user") &&$key!="username" &&$key!="exception" &&$key!="username" &&$key!="exception")
+            		<input type="hidden" name="$key" value="$!turbineUtils.escapeHTML($!data.getParameters().getString($key))">	
+          	#end
         #end
           <input type="submit" value="Login">
         </font>
       </td>
     </tr>
    </table>
-</form>
+</form>

plugin-resources/webapp/xnat-templates/screens/login_row.vm

         <font face="$ui.sansSerifFonts">
         #foreach($key in $data.getParameters().getKeys())
         	#if ($key!="action" && $key!="template" &&$key!="password" &&$key!="username" &&$key!="exception")
-        	<input type="hidden" name="$key" value="$turbineUtils.escapeHTML($data.getParameters().getString($key))">	
+        	<input type="hidden" name="$key" value="$!turbineUtils.escapeHTML($!data.getParameters().getString($key))">	
         	#end
         #end
           <input type="submit" value="Login">
       </td>
     </tr>
    </table>
-</form>
+</form>

plugin-resources/webapp/xnat-templates/screens/register_box.vm

         <input type="hidden" name="xdat:user.primary_password.encrypt" value="true">
         #foreach($key in $data.getParameters().getKeys())
         	#if ($key!="action" && $key!="template" &&$key!="password" &&!$key.startsWith("xdat:user") &&$key!="username" &&$key!="exception")
-        		<input type="hidden" name="$key" value="$turbineUtils.escapeHTML($data.getParameters().getString($key))">	
+        		<input type="hidden" name="$key" value="$!turbineUtils.escapeHTML($!data.getParameters().getString($key))">	
         	#end
         #end
-              </form>
+              </form>

plugin-resources/webapp/xnat-templates/screens/xnat_mrSessionData/edit/scans.vm

 	  #foreach($scani in [0..$TOP_SCAN])
     #set($scan=$om.getSortedScans().get($scani))
     var tempScan = window.classMapping.newInstance("$!scan.getXSIType()");
-    tempScan.setProperty("ID","$!scan.getId()");
-    tempScan.setProperty("type","$!scan.getType()");
-    tempScan.setProperty("quality","$!scan.getQuality()");
-    tempScan.setProperty("note","$!scan.getNote()");
-    tempScan.setProperty("series_description","$!scan.getSeriesDescription()");
-    tempScan.setProperty("parameters/scanTime","$!scan.getParameters_scantime()");
-		    tempScan.setProperty("parameters/imageType","$!scan.getParameters_imagetype()");
-		    tempScan.setProperty("parameters/scanSequence","$!scan.getParameters_scansequence()");
-		    tempScan.setProperty("parameters/seqVariant","$!scan.getParameters_seqvariant()");
-		    tempScan.setProperty("parameters/scanOptions","$!scan.getParameters_scanoptions()");
-		    tempScan.setProperty("parameters/acqType","$!scan.getParameters_acqtype()");
-		    tempScan.setProperty("frames","$!scan.getFrames()");
-		    tempScan.setProperty("parameters/flip","$!scan.getParameters_flip()");
+    tempScan.setProperty("ID","$!turbineUtils.escapeJS($!scan.getId())"); 
+    tempScan.setProperty("type","$!turbineUtils.escapeJS($!scan.getType())");
+    tempScan.setProperty("quality","$!turbineUtils.escapeJS($!scan.getQuality())");
+    tempScan.setProperty("note","$!turbineUtils.escapeJS($!scan.getNote())");
+    tempScan.setProperty("series_description","$!turbineUtils.escapeJS($!scan.getSeriesDescription())");
+    tempScan.setProperty("parameters/scanTime","$!turbineUtils.escapeJS($!scan.getParameters_scantime())");
+		    tempScan.setProperty("parameters/imageType","$!turbineUtils.escapeJS($!scan.getParameters_imagetype())");
+		    tempScan.setProperty("parameters/scanSequence","$!turbineUtils.escapeJS($!scan.getParameters_scansequence())");
+		    tempScan.setProperty("parameters/seqVariant","$!turbineUtils.escapeJS($!scan.getParameters_seqvariant())");
+		    tempScan.setProperty("parameters/scanOptions","$!turbineUtils.escapeJS($!scan.getParameters_scanoptions())");
+		    tempScan.setProperty("parameters/acqType","$!turbineUtils.escapeJS($!scan.getParameters_acqtype())");
+		    tempScan.setProperty("frames","$!turbineUtils.escapeJS($!scan.getFrames())");
+		    tempScan.setProperty("parameters/flip","$!turbineUtils.escapeJS($!scan.getParameters_flip())");
     tempScan.stats="$!scanprops.get($scani).get("files") files, $!scanprops.get($scani).get("size") MB";
     tempScan.setProperty("xnat_imageScanData_id","$!scan.getProperty('xnat_imagescandata_id')");
     window.scanSet.scans.push(tempScan);
       }
    #end
   #end
-  
+   
   window.scanSet.onLoad.subscribe(function(obj){
     var listing=new scanListingEditor("scan_tbody",this);
     listing.render();

plugin-resources/webapp/xnat-templates/screens/xnat_petSessionData/xnat_petSessionData_keyFields.vm

 						#if($!item.getProperty("xnat:petSessionData/start_time_scan"))
 							<TR><TH align="left">Emission Scan Time</TH><TD>$!item.getProperty("xnat:petSessionData/start_time_scan")</TD></TR>
 							#end
+						
+						#if($!item.getProperty("xnat:petSessionData/blood_glucose"))
+							<TR><TH align="left">Blood Glucose Level</TH>
+								<TD>
+									$!item.getProperty("xnat:petSessionData/blood_glucose")&nbsp;
+									$!item.getProperty("xnat:petSessionData/blood_glucose_units")
+								</TD>
+							</TR>
+							#end
+						#if($!item.getProperty("xnat:petSessionData/blood_glucose_collection_time"))
+							<TR><TH align="left">Blood Glucose Collection Time</TH><TD>$!item.getProperty("xnat:petSessionData/blood_glucose_collection_time")</TD></TR>
+							#end
     </table>
    </span>
   </TD>

plugin-resources/webapp/xnat-templates/screens/xnat_subjectAssessorData/upload/xnat_subjectAssessorData_projSubj.vm

  <tr>
   <td align="left" colspan="3"><div style="color:red" id="subj_msg"></div></td>
  </tr>
- <tr>
-  <th align="left">Session</th>
-  <td><input type="text" id="$!item.getXSIType()/label" name="$!item.getXSIType()/label" value="$!item.getProperty("label")"  onkeyup="this.value=fixSessionID(this.value);verifyExptId(this);if(this.validated==false)confirmValues(false);" onblur="confirmValues(false);"/></td>
-  <td id="label_msg"></td>
- </tr>
+#parse($turbineUtils.getTemplateName("_session.vm",$om.getXSIType(),$project,"upload"))
 		<script type="text/javascript" LANGUAGE="javascript" src="$content.getURI('scripts/subjectAssessorData/proj_subj_selector.js')"></SCRIPT>
 <script type="text/javascript">
 var elementName="$!item.getXSIType()";

plugin-resources/webapp/xnat-templates/screens/xnat_subjectAssessorData/upload/xnat_subjectAssessorData_session.vm

+ <tr>
+  <th align="left">Session</th>
+  <td><input type="text" id="$!item.getXSIType()/label" name="$!item.getXSIType()/label" value="$!item.getProperty("label")"  onkeyup="this.value=fixSessionID(this.value);verifyExptId(this);if(this.validated==false)confirmValues(false);" onblur="confirmValues(false);"/></td>
+  <td id="label_msg"></td>
+ </tr>

plugin-resources/webapp/xnat-templates/screens/xnat_subjectData/xnat_subjectData_edit_keyFields.vm

 <DIV class="edit_header1">Demographics</DIV><BR>
 <table>
 	#parse("/screens/xnat_subjectData/xnat_subjectData_edit_core_demographics.vm")
-	#parse("/screens/xnat_subjectData/xnat_subjectData_edit_addtl_demographics.vm")
+	#parse($turbineUtils.getTemplateName("_edit_addtl_demographics","xnat:subjectData",$project))
 </table>
 		<script type="text/javascript">
 		function validateKeyFields(){

plugin-resources/webapp/xnat/applet/DicomUtils-1.0.jar

Binary file modified.

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

 import java.net.URI;
 import java.net.URISyntaxException;
 import java.sql.SQLException;
+import java.text.DateFormat;
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Collection;
 import java.util.Date;
 import java.util.Enumeration;
         return null;
     }
 
-
+	public String getFreeFormDate(String dateParam){
+		try{
+			Date now = Calendar.getInstance().getTime();
+			DateFormat dateFormat = new SimpleDateFormat(dateParam);
+			String dateStr = dateFormat.format(now); 
+			return dateStr;
+		} catch (Exception e1) {logger.error(e1);return null;}
+	}
 
     Hashtable fieldsByName = null;
     public Hashtable getFieldsByName(){

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

         	cc.addClause("xnat:subjectData/sharing/share/project", this.getId());
         	_participants= XnatSubjectdata.getXnatSubjectdatasByField(cc, user, false);
     	}
-    	
+
     	return _participants;
     }
 
         	cc.addClause("xnat:experimentData/sharing/share/project", this.getId());
         	_experiments= XnatExperimentdata.getXnatExperimentdatasByField(cc, user, false);
     	}
-    	
+
     	return _experiments;
     }
 
     	return typed;
     }
 
-    
+
     Hashtable<String,XnatProjectdataField> fieldsByName = null;
     public Hashtable getFieldsByName(){
         if (fieldsByName == null){
 
 
     public ArrayList<String> getOwners() throws Exception{
-        final XFTTable table2 = XFTTable.Execute("SELECT DISTINCT email FROM xdat_element_access ea LEFT JOIN xdat_field_mapping_set fms ON ea.xdat_element_access_id=fms.permissions_allow_set_xdat_elem_xdat_element_access_id LEFT JOIN xdat_field_mapping fm ON fms.xdat_field_mapping_set_id=fm.xdat_field_mapping_set_xdat_field_mapping_set_id LEFT JOIN xdat_user u ON ea.xdat_user_xdat_user_id=u.xdat_user_id WHERE read_element=1 AND delete_element=1 AND login !='guest' AND element_name='xnat:subjectData' AND field_value='" + getId() +  "' ORDER BY email;", getDBName(), null);
+        final XFTTable table2 = XFTTable.Execute("SELECT DISTINCT email FROM xdat_element_access ea LEFT JOIN xdat_field_mapping_set fms ON ea.xdat_element_access_id=fms.permissions_allow_set_xdat_elem_xdat_element_access_id LEFT JOIN xdat_field_mapping fm ON fms.xdat_field_mapping_set_id=fm.xdat_field_mapping_set_xdat_field_mapping_set_id LEFT JOIN xdat_userGroup ug ON ea.xdat_usergroup_xdat_usergroup_id=ug.xdat_usergroup_id LEFT JOIN xdat_user_groupid map ON ug.id=map.groupid LEFT JOIN xdat_user u ON map.groups_groupid_xdat_user_xdat_user_id=u.xdat_user_id  WHERE read_element=1 AND delete_element=1 AND login !='guest' AND element_name='xnat:subjectData' AND field_value='" + getId() +  "' ORDER BY email;", getDBName(), null);
         return table2.convertColumnToArrayList("email");
     }
 
     public ArrayList<String> getMembers() throws Exception{
-    	final XFTTable table1 = XFTTable.Execute("SELECT DISTINCT email FROM xdat_element_access ea LEFT JOIN xdat_field_mapping_set fms ON ea.xdat_element_access_id=fms.permissions_allow_set_xdat_elem_xdat_element_access_id LEFT JOIN xdat_field_mapping fm ON fms.xdat_field_mapping_set_id=fm.xdat_field_mapping_set_xdat_field_mapping_set_id LEFT JOIN xdat_user u ON ea.xdat_user_xdat_user_id=u.xdat_user_id WHERE edit_element=1 AND login !='guest' AND element_name='xnat:subjectData' AND field_value='" + getId() +  "' ORDER BY email;", getDBName(), null);
+    	final XFTTable table1 = XFTTable.Execute("SELECT DISTINCT email FROM xdat_element_access ea LEFT JOIN xdat_field_mapping_set fms ON ea.xdat_element_access_id=fms.permissions_allow_set_xdat_elem_xdat_element_access_id LEFT JOIN xdat_field_mapping fm ON fms.xdat_field_mapping_set_id=fm.xdat_field_mapping_set_xdat_field_mapping_set_id LEFT JOIN xdat_userGroup ug ON ea.xdat_usergroup_xdat_usergroup_id=ug.xdat_usergroup_id LEFT JOIN xdat_user_groupid map ON ug.id=map.groupid LEFT JOIN xdat_user u ON map.groups_groupid_xdat_user_xdat_user_id=u.xdat_user_id  WHERE edit_element=1 AND login !='guest' AND element_name='xnat:subjectData' AND field_value='" + getId() +  "' ORDER BY email;", getDBName(), null);
         return table1.convertColumnToArrayList("email");
     }
 
     public ArrayList<String> getCollaborators() throws Exception{
-    	final XFTTable table2 = XFTTable.Execute("SELECT DISTINCT email FROM xdat_element_access ea LEFT JOIN xdat_field_mapping_set fms ON ea.xdat_element_access_id=fms.permissions_allow_set_xdat_elem_xdat_element_access_id LEFT JOIN xdat_field_mapping fm ON fms.xdat_field_mapping_set_id=fm.xdat_field_mapping_set_xdat_field_mapping_set_id LEFT JOIN xdat_user u ON ea.xdat_user_xdat_user_id=u.xdat_user_id WHERE read_element=1 AND edit_element=0 AND login !='guest' AND element_name='xnat:subjectData' AND field_value='" + getId() +  "' ORDER BY email;", getDBName(), null);
+    	final XFTTable table2 = XFTTable.Execute("SELECT DISTINCT email FROM xdat_element_access ea LEFT JOIN xdat_field_mapping_set fms ON ea.xdat_element_access_id=fms.permissions_allow_set_xdat_elem_xdat_element_access_id LEFT JOIN xdat_field_mapping fm ON fms.xdat_field_mapping_set_id=fm.xdat_field_mapping_set_xdat_field_mapping_set_id LEFT JOIN xdat_userGroup ug ON ea.xdat_usergroup_xdat_usergroup_id=ug.xdat_usergroup_id LEFT JOIN xdat_user_groupid map ON ug.id=map.groupid LEFT JOIN xdat_user u ON map.groups_groupid_xdat_user_xdat_user_id=u.xdat_user_id  WHERE read_element=1 AND edit_element=0 AND login !='guest' AND element_name='xnat:subjectData' AND field_value='" + getId() +  "' ORDER BY email;", getDBName(), null);
         return table2.convertColumnToArrayList("email");
     }
 //
         final ArcProject arcProj = this.getArcSpecification();
 
 		if (arcProj==null) return "arc001";
-		
+
         path = arcProj.getCurrentArc();
         if (path==null || path.equals("")){
             path="arc001";
         {
             try {
 				if (es.isSecure() && (es.getSchemaElement().getGenericXFTElement().instanceOf("xnat:subjectData") || es.getSchemaElement().getGenericXFTElement().instanceOf("xnat:experimentData"))){
-					
+
 				    es.initPSF(es.getElementName() + "/project");
 				    es.initPSF(es.getElementName() + "/sharing/share/project");
 				}else{
 		} catch (Exception e1) {
             logger.error("",e1);
 		}
-		
+
         //init members
         ArrayList member = XdatUsergroup.getXdatUsergroupsByField(XdatUsergroup.SCHEMA_ELEMENT_NAME +".ID", this.getId() + "_" + MEMBER_GROUP, this.getUser(), true);
 
 		} catch (Exception e2) {
             logger.error("",e2);
 		}
-		
+
         if (XFT.VERBOSE)System.out.println("Group init() MEMBER: " + (Calendar.getInstance().getTimeInMillis()-startTime) + "ms");
 
         //init collaborators
 		} catch (Exception e2) {
             logger.error("",e2);
 		}
-		
+
         if (XFT.VERBOSE)System.out.println("Group init(): " + (Calendar.getInstance().getTimeInMillis()-startTime) + "ms");
     }
 
 
         return null;
     }
-    
+
 
     public ArrayList<XdatStoredSearch> getBundles(){
     	ArrayList<XdatStoredSearch> searches = XdatStoredSearch.GetSearches("xdat:stored_search/tag", this.getId(), true);
-    	
+
     	Hashtable<String,Long> counts=this.getExperimentCountByXSIType();
-    	
+
     	boolean matched=false;
     	for(XdatStoredSearch xss:searches){
     		if(xss.getRootElementName().equalsIgnoreCase("xnat:subjectData")){
     			break;
     		}
     	}
-    	
+
     	if(!matched){
     		XnatAbstractprotocol protocol = this.getProtocolByDataType("xnat:subjectData");
     		XdatStoredSearch xss=null;
     		xss.setId("@xnat:subjectData");
     		searches.add(xss);
     	}
-    	
+
     	for(String key:counts.keySet()){
     		matched=false;
         	for(XdatStoredSearch xss:searches){
         			break;
         		}
         	}
-        	
+
         	if(!matched){
         		XnatAbstractprotocol protocol = this.getProtocolByDataType(key);
         		XdatStoredSearch xss=null;
         		searches.add(xss);
         	}
     	}
-    	
+
         return searches;
     }
-    
+
 
 
     public XdatStoredSearch getDefaultSearch(String elementName){
             xss=this.getDefaultSearch(elementName,this.getId()+"_"+elementName);
 
 			xss.setId(this.getId()+"_"+elementName);
-			
+
 			ElementSecurity es=ElementSecurity.GetElementSecurity(elementName);
-			
+
 			if(es!=null)
 				xss.setBriefDescription(es.getPluralDescription());
 			else{
 			}
 			xss.setSecure(false);
 			xss.setAllowDiffColumns(false);
-			xss.setTag(this.getId()); 
-            
+			xss.setTag(this.getId());
+
             UserI user = this.getUser();
-            
+
             XnatAbstractprotocol protocol = this.getProtocolByDataType(elementName);
     		if(protocol!=null){
     			if(protocol instanceof XnatDatatypeprotocol)
     	                if (field.getType().equals("custom"))
     	                {
     	                    fieldID=((XnatDatatypeprotocol)protocol).getDatatypeSchemaElement().getSQLName().toUpperCase() + "_FIELD_MAP="+field.getName().toLowerCase();
-    	                    
+
     	                }else{
     	                    try {
     	                        SchemaElement se=SchemaElement.GetElement(((XnatDatatypeprotocol)protocol).getDataType());
-    	                        
+
     	                        try {
     	                            DisplayField df=se.getDisplayFieldForXMLPath(field.getXmlpath());
     	                            if (df!=null){
     	                        logger.error("",e);
     	                    }
     	                }
-    	                    
+
     	                if (fieldID!=null){
     	                    xsf.setFieldId(fieldID);
 
                     }
                 }
             }
-            
+
         } catch (Exception e) {
             logger.error("",e);
         }
 //                    try {
 //                        XdatStoredSearch xss = protocol.getDefaultSearch((XnatProjectdata)this);
 //
-//                        
+//
 //                        xss.save(this.getUser(), true, true);
 //
 //
 //                        //XdatStoredSearch.GetPreLoadedSearches().add(xss);
 //                        modified=true;
-//                        
+//
 //                        final String[] groups = {getId() + "_" + OWNER_GROUP,getId() + "_" + MEMBER_GROUP,getId() + "_" + COLLABORATOR_GROUP};
 //
 //                        for(int i=0;i<groups.length;i++){
             if (projectAccess==1){
 
                 query = "SELECT read_element FROM xdat_element_access ea LEFT JOIN xdat_field_mapping_set fms ON ea.xdat_element_access_id=fms.permissions_allow_set_xdat_elem_xdat_element_access_id LEFT JOIN xdat_user u ON ea.xdat_user_xdat_user_id=u.xdat_user_id LEFT JOIN xdat_field_mapping fm ON fms.xdat_field_mapping_set_id=fm.xdat_field_mapping_set_xdat_field_mapping_set_id WHERE login='guest' AND element_name!='xnat:projectData' AND field_value='" + getId() +  "';";
-  
+
                 Integer subjectAccess = (Integer)PoolDBUtils.ReturnStatisticQuery(query, "read_element", getDBName(), null);
                 if (subjectAccess!=null)
                 {
                         guest = new XDATUser("guest");
                     }
                     ArrayList<ElementSecurity> securedElements = ElementSecurity.GetSecureElements();
-                    
+
                     if (accessibility.equals("public"))
                     {
                         //public
                         guest.setPermissions("xnat:projectData", "xnat:projectData/ID", this.getId(), false, true, false, false, true,true);
-                        
+
                         for (ElementSecurity es: securedElements)
                         {
                         	if (es.hasField(es.getElementName() + "/project") && es.hasField(es.getElementName() + "/sharing/share/project")){
         group.setId(getId() + "_" + OWNER_GROUP);
         group.setDisplayname("Owners");
         group.setTag(getId());
-        
+
         UserGroup ownerG=UserGroupManager.GetGroup(group.getId());
         if(ownerG==null){
         	group.save(this.getUser(), true, true);
                 ((XDATUser)user).getGroups().put(group.getId(),ug);
 
                 this.addGroupMember(this.getId() + "_" + OWNER_GROUP, (XDATUser)user, (XDATUser)user);
-            } 
+            }
         }
 
         return super.save(user, overrideSecurity, allowItemRemoval);
 
         }
     }
-    
+
     public void initNewProject(XDATUser user,boolean allowDataDeletion,boolean allowMatchingID) throws Exception{
     	if (this.getId()==null){
             String secondaryID = this.getSecondaryId();
             if (secondaryID==null){
-                
+
                 throw new Exception("Please define a project abbreviation.");
             }else{
                 setId(secondaryID);
-                
+
                 XFTItem db=getCurrentDBVersion();
                 if (db!=null){
                 	String msg="Project '" + getId() + "' already exists.";
                 	throw new Exception(msg);
                 }
             }
-        }else{          
+        }else{
         	if(!allowMatchingID){
                 XFTItem db=getCurrentDBVersion();
                 if (db!=null){
                 }
         	}
         }
-    	
+
     	if(this.getSecondaryId()==null){
     		this.setSecondaryId(this.getId());
     	}
-    	
+
     	if(this.getName()==null){
     		this.setName(this.getId());
     	}
 
     	if(this.getStudyprotocol().size()>0){
         	Hashtable<String,ElementSecurity> ess = ElementSecurity.GetElementSecurities();
-            
+
             int index = 0;
             for (XnatAbstractprotocol  protocol:this.getStudyprotocol()){
                 if(protocol.getProperty("data-type")==null){
                                 logger.error("",e);
                             }
                         }
-                        
+
                         getItem().removeChild("xnat:projectData/studyProtocol", getItem().getChildItems("xnat:projectData/studyProtocol").indexOf(protocol));
                 	}
                 }else{
                     if (protocol.getProperty("name")==null){
                         protocol.setProperty("name",ess.get(e.getFullXMLName()).getPluralDescription());
                     }
-                    
+
                     if(protocol.getXSIType().equals("xnat:datatypeProtocol")){
                         protocol.setProperty("xnat:datatypeProtocol/definitions/definition[ID=default]/data-type", protocol.getProperty("data-type"));
                         protocol.setProperty("xnat:datatypeProtocol/definitions/definition[ID=default]/project-specific", "false");
                 index++;
             }
     	}
-        
+
         for(XnatInvestigatordata inv:this.getInvestigators_investigator()){
         	if(inv.getFirstname()==null){
         		XFTItem temp = inv.getCurrentDBVersion();
         		inv.setLastname(temp.getStringProperty("lastname"));
         	}
         }
-        
+
         for(XnatInvestigatordata inv:this.getInvestigators_investigator()){
         	if(inv.getFirstname()==null){
         		XFTItem temp = inv.getCurrentDBVersion();
         	}
         }
     }
-    
+
     public void initArcProject(ArcProject arcP, XDATUser user) throws Exception{
     	if(arcP==null){
     		 XFTItem item = XFTItem.NewItem("arc:project", user);
     	}
     	arcP.setProperty("projects_project_arc_archivespe_arc_archivespecification_id", ArcSpecManager.GetInstance().getArcArchivespecificationId());
         arcP.setId(getId());
-        
+
         arcP.setProperty("arc:project/paths/archivePath", ArcSpecManager.GetInstance().getGlobalArchivePath() + getId()+"/");
         arcP.setProperty("arc:project/paths/prearchivePath", ArcSpecManager.GetInstance().getGlobalPrearchivePath() + getId()+"/");
         arcP.setProperty("arc:project/paths/cachePath", ArcSpecManager.GetInstance().getGlobalCachePath() + getId()+"/");
         arcP.setProperty("arc:project/paths/buildPath", ArcSpecManager.GetInstance().getGlobalBuildPath() + getId()+"/");
-                
+
         arcP.save(user, true, false);
         ArcSpecManager.Reset();
     }
-    
+
     public XdatStoredSearch getDefaultSearch(String dataType,String id){
     	XdatStoredSearch xss=null;
     	try {
 			CriteriaCollection cc = new CriteriaCollection("OR");
 			cc.addClause(dataType+"/sharing/share/project", "=", getId());
 			cc.addClause(dataType+".PROJECT", "=", getId());
-			
+
 			search.addCriteria(cc);
-			
+
 			xss = search.convertToStoredSearch(id);
 
 			Iterator fields = xss.getSearchFields().iterator();
 		}
 		return xss;
     }
-    
+
     public static String CleanID(String s){
     	s=s.replace('`', '_');
     	s=s.replace('~', '_');
     	s=s.replace('/', '_');
     	return s;
     }
-    
 
-    
+
+
     public String canDelete(XDATUser user) {
     	try {
 			if(!user.canDelete(this.getItem())){
 			e.printStackTrace();
 			return "Invalid delete permissions for this project.";
 		}
-			
+
 		for(XnatSubjectdata sub: this.getParticipants_participant()){
 			String msg=sub.canDelete(this,user);
 			if(msg!=null){
 				return msg;
 			}
 		}
-		
+
 		return null;
     }
-    
+
     public void deleteFiles() throws IOException{
     	String archive=this.getRootArchivePath();
     	File dir=new File(archive);
     	if(dir.exists()){
     		FileUtils.MoveToCache(dir);
     	}
-    	
+
     	for(XnatAbstractresource abstRes:this.getResources_resource()){
     		abstRes.deleteFromFileSystem(archive);
     	}
     }
-    
-    public String delete(XDATUser user, boolean removeFiles){    	
+
+    public String delete(XDATUser user, boolean removeFiles){
     	String msg=this.canDelete(user);
     	if(msg!=null){
     		logger.error(msg);
     		return msg;
     	}
-    	
+
 		try {
-		
+
 			if(!user.canDelete(this)){
 				return "User account doesn't have permission to delete this project.";
 			}
-						
+
 			if(removeFiles){
 				this.deleteFiles();
 			}
 	            msg=sub.delete(this,user,removeFiles);
 	            if(msg!=null)return msg;
 	        }
-	        
+
 	        user.clearLocalCache();
 			MaterializedView.DeleteByUser(user);
-			
+
 	        DBAction.DeleteItem(getItem().getCurrentDBVersion(), user);
-	            
+
 	        //DELETE field mappings
 	        ItemSearch is = ItemSearch.GetItemSearch("xdat:field_mapping", user);
 	        is.addCriteria("xdat:field_mapping.field_value", getId());
 	            XFTItem item = (XFTItem)items.next();
 	            DBAction.DeleteItem(item, user);
 	        }
-	        
+
 	        //DELETE user.groupId
 	        CriteriaCollection col = new CriteriaCollection("AND");
 	        col.addClause(XdatUserGroupid.SCHEMA_ELEMENT_NAME +".groupid"," LIKE ", getId() + "_%");
 	        Iterator groups = XdatUserGroupid.getXdatUserGroupidsByField(col, user, false).iterator();
-	        
+
 	        while(groups.hasNext()){
 	            XdatUserGroupid g = (XdatUserGroupid)groups.next();
 	            try {
 	                logger.error("",e);
 	            }
 	        }
-	        
+
 	        //DELETE user groups
 	        col = new CriteriaCollection("AND");
 	        col.addClause(XdatUsergroup.SCHEMA_ELEMENT_NAME +".ID"," LIKE ", getId() + "_%");
 	        groups = XdatUsergroup.getXdatUsergroupsByField(col, user, false).iterator();
-	        
+
 	        while(groups.hasNext()){
 	            XdatUsergroup g = (XdatUsergroup)groups.next();
 	            try {
 	                logger.error("",e);
 	            }
 	        }
-	        
+
 	        //DELETE storedSearches
 	        Iterator bundles=getBundles().iterator();
 	        while (bundles.hasNext())
 	                logger.error("",e);
 	            }
 	        }
-	        
+
 	        ArcProject p =getArcSpecification();
 	        try {
 	            if (p!=null)DBAction.DeleteItem(p.getItem(), user);
 		}
     	return null;
     }
-    
+
     public void delete(boolean removeFiles, XDATUser user)throws SQLException,Exception{
     	boolean preventProjectDelete=false;
         boolean preventProjectDeleteByP=false;
-    	for (XnatSubjectdata subject : getParticipants_participant()){            
+    	for (XnatSubjectdata subject : getParticipants_participant()){
             if (subject!=null){
             	boolean preventSubjectDelete=false;
             	boolean preventSubjectDeleteByP=false;
                final  ArrayList<XnatSubjectassessordata> expts = subject.getExperiments_experiment();
-               
+
                if(!(preventSubjectDelete || preventSubjectDeleteByP) && expts.size()!=subject.getSubjectAssessorCount()){
                	preventSubjectDelete=true;
                }
-               
+
                 for (XnatSubjectassessordata exptI : expts){
                     final XnatSubjectassessordata expt = (XnatSubjectassessordata)exptI;
 
                         if(user.canDelete(expt)){
                             if (removeFiles){
                             	final List<XFTItem> hash = expt.getItem().getChildrenOfType("xnat:abstractResource");
-                                
+
                                 for (XFTItem resource : hash){
                                     ItemI om = BaseElement.GetGeneratedItem((XFTItem)resource);
                                     if (om instanceof XnatAbstractresource){
                     		}
                     	}
                     }
-                    
+
                 }
-                
-                
+
+
             	if(!subject.getProject().equals(getId())){
             		for(XnatProjectparticipant pp : subject.getSharing_share()){
                 		if(pp.getProject().equals(getId())){
                 		if(user.canDelete(subject)){
                             if (removeFiles){
                             	final List<XFTItem> hash = subject.getItem().getChildrenOfType("xnat:abstractResource");
-                                
+
                                 for (XFTItem resource : hash){
                                     ItemI om = BaseElement.GetGeneratedItem((XFTItem)resource);
                                     if (om instanceof XnatAbstractresource){
                 	}
             	}
             }
-        } 
+        }
 
 	    user.clearLocalCache();
 		MaterializedView.DeleteByUser(user);
-		
+
 		if (!preventProjectDelete && !preventProjectDeleteByP){
 	        DBAction.DeleteItem(getItem().getCurrentDBVersion(), user);
-	            
+
 	        //DELETE field mappings
 	        ItemSearch is = ItemSearch.GetItemSearch("xdat:field_mapping", user);
 	        is.addCriteria("xdat:field_mapping.field_value", getId());
 	            XFTItem item = (XFTItem)items.next();
 	            DBAction.DeleteItem(item, user);
 	        }
-	        
+
 	        //DELETE user.groupId
 	        CriteriaCollection col = new CriteriaCollection("AND");
 	        col.addClause(XdatUserGroupid.SCHEMA_ELEMENT_NAME +".groupid"," LIKE ", getId() + "_%");
 	        Iterator groups = XdatUserGroupid.getXdatUserGroupidsByField(col, user, false).iterator();
-	        
+
 	        while(groups.hasNext()){
 	            XdatUserGroupid g = (XdatUserGroupid)groups.next();
 	            try {
 	                logger.error("",e);
 	            }
 	        }
-	        
+
 	        //DELETE user groups
 	        col = new CriteriaCollection("AND");
 	        col.addClause(XdatUsergroup.SCHEMA_ELEMENT_NAME +".ID"," LIKE ", getId() + "_%");
 	        groups = XdatUsergroup.getXdatUsergroupsByField(col, user, false).iterator();
-	        
+
 	        while(groups.hasNext()){
 	            XdatUsergroup g = (XdatUsergroup)groups.next();
 	            try {
 	                logger.error("",e);
 	            }
 	        }
-	        
+
 	        //DELETE storedSearches
 	        Iterator bundles=getBundles().iterator();
 	        while (bundles.hasNext())
 	                logger.error("",e);
 	            }
 	        }
-	        
+
 	        ArcProject p =getArcSpecification();
 	        try {
 	            if (p!=null)DBAction.DeleteItem(p.getItem(), user);
 	@Override
 	public void preSave() throws Exception{
 		super.preSave();
-		
+
     	final String archive=this.getRootArchivePath();
 		final String expectedPath=new File(archive,"resources").getAbsolutePath().replace('\\', '/');
-		
+
 		for(final XnatAbstractresource res: this.getResources_resource()){
 			final String uri;
 			if(res instanceof XnatResource){
 			}else{
 				continue;
 			}
-			
+
 			FileUtils.ValidateUriAgainstRoot(uri,expectedPath,"URI references data outside of the project:" + uri);
 		}
 	}
-	
 
-    
+
+
     public String getArchiveDirectoryName(){
     	return this.getId();
     }

plugin-resources/webapp/xnat/java/org/nrg/xnat/archive/AlreadyArchivingException.java

+/**
+ * Copyright (c) 2010 Washington University
+ */
+package org.nrg.xnat.archive;
+
+import org.restlet.data.Status;
+
+/**
+ * Indicates that the session to be archived is already in the transfer pipeline.
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public class AlreadyArchivingException extends ArchivingException {
+	private static final long serialVersionUID = 1L;
+	private static final Status status = Status.CLIENT_ERROR_FORBIDDEN;
+	private static final String message = "Session archiving already in progress";
+	
+	public AlreadyArchivingException() {
+		super(status, message);
+	}
+}

plugin-resources/webapp/xnat/java/org/nrg/xnat/archive/ArchivingException.java

+/**
+ * Copyright (c) 2010 Washington University
+ */
+package org.nrg.xnat.archive;
+
+import org.restlet.data.Status;
+
+/**
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public class ArchivingException extends Exception {
+	private static final long serialVersionUID = 1L;
+	private static final Status DEFAULT_STATUS = Status.SERVER_ERROR_INTERNAL;
+	private final Status status;
+	
+	public ArchivingException(Status status) {
+		super();
+		this.status = status;
+	}
+	
+	public ArchivingException() {
+		this(DEFAULT_STATUS);
+	}
+
+	public ArchivingException(Status status, String message) {
+		super(message);
+		this.status = status;
+	}
+	
+	public ArchivingException(String message) {
+		this(DEFAULT_STATUS, message);
+	}
+
+	public ArchivingException(Status status, Throwable cause) {
+		super(cause);
+		this.status = status;
+	}
+	
+	public ArchivingException(Throwable cause) {
+		this(DEFAULT_STATUS, cause);
+	}
+
+	public ArchivingException(Status status, String message, Throwable cause) {
+		super(message, cause);
+		this.status = status;
+	}
+
+	public ArchivingException(String message, Throwable cause) {
+		this(DEFAULT_STATUS, message, cause);
+	}
+
+	/**
+	 * What is the HTTP Status code for the response?
+	 * @return Restlet wrapper around an HTTP status code
+	 */
+	public final Status getStatus() {
+		return status;
+	}
+}

plugin-resources/webapp/xnat/java/org/nrg/xnat/archive/DuplicateSessionLabelException.java

+/**
+ * Copyright (c) 2010 Washington University
+ */
+package org.nrg.xnat.archive;
+
+import org.restlet.data.Status;
+
+/**
+ * Indicates that the label of a session to be archived has already been
+ * used for an archived session in the same project.
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public class DuplicateSessionLabelException extends ArchivingException {
+	private final static long serialVersionUID = 1L;
+	private final static Status status = Status.CLIENT_ERROR_FORBIDDEN;
+	private final static String format = "session label %s already used in project %s";
+	
+	public DuplicateSessionLabelException() {
+		super(status);
+	}
+
+	public DuplicateSessionLabelException(String session, String project) {
+		super(status, String.format(format, session, project));
+	}
+}

plugin-resources/webapp/xnat/java/org/nrg/xnat/archive/PrearcSessionArchiver.java

+/**
+ * Copyright (c) 2010 Washington University
+ */
+package org.nrg.xnat.archive;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.concurrent.Callable;
+
+import org.apache.commons.collections.MultiHashMap;
+import org.apache.commons.collections.MultiMap;
+import org.nrg.StatusListener;
+import org.nrg.StatusMessage;
+import org.nrg.StatusMessage.Status;
+import org.nrg.xdat.om.WrkWorkflowdata;
+import org.nrg.xdat.om.XnatAbstractresource;
+import org.nrg.xdat.om.XnatExperimentdata;
+import org.nrg.xdat.om.XnatImagescandata;
+import org.nrg.xdat.om.XnatImagesessiondata;
+import org.nrg.xdat.om.XnatProjectdata;
+import org.nrg.xdat.om.XnatResource;
+import org.nrg.xdat.om.XnatSubjectdata;
+import org.nrg.xdat.security.XDATUser;
+import org.nrg.xdat.turbine.utils.AdminUtils;
+import org.nrg.xdat.turbine.utils.TurbineUtils;
+import org.nrg.xft.db.MaterializedView;
+import org.nrg.xft.search.CriteriaCollection;
+import org.nrg.xft.security.UserI;
+import org.nrg.xft.utils.FileUtils;
+import org.nrg.xft.utils.ValidationUtils.ValidationResults;
+import org.nrg.xnat.exceptions.InvalidArchiveStructure;
+import org.nrg.xnat.turbine.modules.actions.LoadImageData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public final class PrearcSessionArchiver implements Callable<URL> {
+	private static final String[] SCANS_DIR_NAMES = {"SCANS", "RAW"};
+	
+	public static final String PARAM_SESSION = "session";
+	public static final String PARAM_SUBJECT = "subject";
+
+	private final Logger logger = LoggerFactory.getLogger(PrearcSessionArchiver.class);
+	private final Collection<StatusListener> listeners = new LinkedHashSet<StatusListener>();
+	private final Object statusObj;
+	private final XnatImagesessiondata session;
+	private final XDATUser user;
+	private final String project;
+	private final MultiMap params;
+	
+	private boolean shouldForceQuarantine = false;
+	
+
+	public PrearcSessionArchiver(final XnatImagesessiondata session,
+			final XDATUser user, final String project,
+			final MultiMap params) {
+		this.session = session;
+		this.user = user;
+		this.project = project;
+		this.statusObj = session.getPrearchivePath();
+		this.params = new MultiHashMap(params);
+	}
+
+	public PrearcSessionArchiver(final File sessionDir,
+			final XDATUser user, final String project,
+			final MultiMap params)
+	throws IOException,SAXException {
+		this(loadSession(sessionDir, user, project), user, project, params);
+	}
+
+	private static XnatImagesessiondata loadSession(final File sessionDir,
+			final XDATUser user, final String project)
+	throws IOException,SAXException {
+		final LoadImageData loader = new LoadImageData();
+		final File sessionXML = new File(sessionDir.getPath() + ".xml");
+		return loader.getSession(user, sessionXML, project, false);
+	}
+
+
+	public boolean addStatusListener(final StatusListener listener) {
+		return listeners.add(listener);
+	}
+
+	public boolean removeStatusListener(final StatusListener listener) {
+		return listeners.remove(listener);
+	}
+
+	public void clearStatusListeners() {
+		listeners.clear();
+	}
+
+	
+	public boolean forceQuarantine(final boolean shouldForce) {
+		final boolean prev = this.shouldForceQuarantine;
+		this.shouldForceQuarantine = shouldForce;
+		return prev;
+	}
+	
+	private void report(final Status status, final String message) {
+		for (final StatusListener listener : listeners) {
+			listener.notify(new StatusMessage(statusObj, status, message));
+		}
+	}
+
+	private void processing(final String message) {
+		report(Status.PROCESSING, message);
+	}
+
+	private void warning(final String message) {
+		report(Status.WARNING, message);
+	}
+
+	private void failed(final String message) {
+		report(Status.FAILED, message);
+	}
+
+	private void completed(final String message) {
+		report(Status.COMPLETED, message);
+	}
+	
+	/**
+	 * Determine an appropriate session label.
+	 * @throws ArchivingException
+	 */
+	private void fixSessionLabel() throws ArchivingException {
+		if (params.containsKey(PARAM_SESSION)) {
+			final String label = (String)getFirstOf(params, PARAM_SESSION);
+			if (null != label) {
+				session.setLabel(XnatImagesessiondata.cleanValue(label));
+			}
+		}
+		if (!LoadImageData.hasValue(session.getLabel())) {
+			if (LoadImageData.hasValue(session.getDcmpatientid())) {
+				session.setLabel(XnatImagesessiondata.cleanValue(session.getDcmpatientid()));
+			}
+		}
+		if (!LoadImageData.hasValue(session.getLabel())) {
+			failed("unable to deduce session label");
+			throw new ArchivingException("unable to deduce session label");
+		}		
+	}
+	
+	private static Object getFirstOf(final Iterator<?> i) {
+		while (i.hasNext()) {
+			final Object o = i.next();
+			if (null != o) {
+				return o;
+			}
+		}
+		return null;
+	}
+	
+	private static Object getFirstOf(final MultiMap m, final Object key) {
+		final Collection<?> vals = (Collection<?>)m.get(key);
+		return null == vals ? null : getFirstOf(vals.iterator());
+	}
+	
+	/**
+	 * Ensure that the subject label and ID are set in the session --
+	 * by deriving and setting them, if necessary.
+	 * @throws ArchivingException
+	 */
+	private void fixSubject() throws ArchivingException {
+		if (params.containsKey(PARAM_SUBJECT)) {
+			final String paramLabel = (String)getFirstOf(params, PARAM_SUBJECT);
+			if (null != paramLabel) {
+				session.setSubjectId(paramLabel);
+			}
+		}
+		final String subjectID = session.getSubjectId();
+
+		processing("looking for subject " + subjectID);
+		XnatSubjectdata subject = session.getSubjectData();
+		if (null == subject && LoadImageData.hasValue(subjectID)) {
+			final String cleaned = XnatSubjectdata.cleanValue(subjectID);
+			if (!cleaned.equals(subjectID)) {
+				session.setSubjectId(cleaned);
+				subject = session.getSubjectData();
+			}
+		}
+
+		if (null == subject) {
+			processing("creating new subject");
+			subject = new XnatSubjectdata((UserI)user);
+			subject.setProject(project);
+			if (LoadImageData.hasValue(subjectID)) {
+				subject.setLabel(XnatSubjectdata.cleanValue(subjectID));
+			}
+			final String newID;
+			try {
+				newID = XnatSubjectdata.CreateNewID();
+			} catch (Throwable e) {
+				failed("unable to create new subject ID");
+				throw new ArchivingException("Unable to create new subject ID", e);
+			}
+			subject.setId(newID);
+			try {
+				subject.save(user, false, false);
+			} catch (Throwable e) {
+				failed("unable to save new subject " + newID);
+				throw new ArchivingException("Unable to save new subject " + subject, e);
+			}
+			processing("created new subject " + subjectID);
+
+			session.setSubjectId(subject.getId());
+		} else {
+			processing("matches existing subject " + subjectID);
+		}
+	}
+	
+	/**
+	 * Retrieves the archive session directory for the given session.
+	 * Verifies that the path will not overwrite data in an existing session.
+	 * @return archive session directory
+	 * @throws ArchivingException
+	 */
+	private File getArcSessionDir()
+	throws ArchivingException {
+		final File currentArcDir;
+		try {
+			final String path = session.getCurrentArchiveFolder();
+			currentArcDir = null == path ? null : new File(path);
+		} catch (InvalidArchiveStructure e) {
+			throw new ArchivingException("couldn't get archive folder for " + session, e);
+		}
+		final String sessDirName = session.getArchiveDirectoryName();
+		final File relativeSessionDir;
+		if (null == currentArcDir) {
+			relativeSessionDir = new File(sessDirName);
+		} else {
+			relativeSessionDir = new File(currentArcDir, sessDirName);
+		}
+		
+		final File rootArchiveDir = new File(session.getPrimaryProject(false).getRootArchivePath());
+		final File arcSessionDir = new File(rootArchiveDir, relativeSessionDir.getPath());
+		
+		// Verify that the proposed archive session directory does not already contain data
+		if (arcSessionDir.exists()) {
+			for (final String scansDirName : SCANS_DIR_NAMES) {
+				final File scansDir = new File(arcSessionDir, scansDirName);
+				if (scansDir.exists() && FileUtils.HasFiles(scansDir)) {
+					failed("project " + project + " already contains a session named " + session.getLabel());
+					throw new DuplicateSessionLabelException(session.getLabel(), project);
+				}
+			}
+		}
+		return arcSessionDir;
+	}
+
+	
+	/**
+	 * Verify that the session isn't already in the transfer pipeline.
+	 * @throws AlreadyArchivingException
+	 */
+	private void preventConcurrentArchiving() throws AlreadyArchivingException {
+		final CriteriaCollection cc= new CriteriaCollection("AND");
+		cc.addClause("wrk:workFlowData.ID",session.getId());
+		cc.addClause("wrk:workFlowData.pipeline_name","Transfer");
+		cc.addClause("wrk:workFlowData.status","In Progress");
+		if (!WrkWorkflowdata.getWrkWorkflowdatasByField(cc, user, false).isEmpty()){
+			throw new AlreadyArchivingException();
+		}	
+	}
+	
+	private static boolean isNullOrEmpty(final String s) {
+		return null == s || "".equals(s);
+	}
+	
+	/**
+	 * Makes the scan paths absolute; also sets the scan content type to RAW if it's not already set.
+	 * @param arcSessionPath
+	 */
+	private void fixScans(final File arcSessionDir) {
+		final String root = arcSessionDir.getPath().replace('\\','/') + "/";
+		for (final XnatImagescandata scan : session.getScans_scan()) {
+			for (final XnatAbstractresource file : scan.getFile()) {
+				// appendToPaths() is poorly named: should maybe be prependPathsWith()
+				file.appendToPaths(root);
+				// TODO: this is surrounded by a try/catch(Throwable) that logs but
+				// TODO: otherwise discards the Throwable. Was this needed?
+				if (isNullOrEmpty(file.getContent())) {
+					((XnatResource)file).setContent("RAW");
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Updates the prearchive session XML, if possible. Errors here are logged but not
+	 * otherwise handled; messing up the prearchive session XML is not a disaster.
+	 * @param prearcSessionPath path of session directory in prearchive
+	 */
+	private void updatePrearchiveSessionXML(final String prearcSessionPath) {
+		final File prearcSessionDir = new File(prearcSessionPath);
+		try {
+			final FileWriter prearcXML = new FileWriter(prearcSessionDir.getPath() + ".xml");
+			try {
+				logger.debug("Preparing to update prearchive XML for {}", session);
+				session.toXML(prearcXML, true);
+			} catch (RuntimeException e) {
+				logger.error("unable to update prearchive session XML", e);
+				warning("updated prearchive session XML could not be written: " + e.getMessage());
+			} catch (SAXException e) {
+				logger.error("attempted to write invalid updated prearchive session XML", e);
+				warning("updated prearchive session XML is invalid: " + e.getMessage());
+			} finally {
+				prearcXML.close();
+			}
+		} catch (FileNotFoundException e) {
+			logger.error("unable to update prearchive session XML", e);
+			warning("prearchive session XML not found, cannot update");
+		} catch (IOException e) {
+			logger.error("error updating prearchive session XML", e);
+			warning("could not update prearchive session XML: " + e.getMessage());
+		}
+	}
+	
+	private boolean doTransfer(final String prearcSessionPath) {
+		final Transfer transfer = new Transfer(TurbineUtils.GetFullServerPath(),
+				TurbineUtils.GetSystemName(),
+				AdminUtils.getAdminEmailId());
+		if (null == session.getUser()) {
+		    session.getItem().setUser(user);
+		}
+		transfer.setImageSession(session);
+		transfer.setPlaceInRaw(false);
+		transfer.setPrearc(prearcSessionPath);
+		return transfer.execute();
+	}
+	
+	/*
+	 * (non-Javadoc)
+	 * @see java.util.concurrent.Callable#call()
+	 */
+	public URL call() throws ArchivingException {
+		fixSessionLabel();
+		fixSubject();
+		
+		final File arcSessionDir = getArcSessionDir();
+		
+
+		processing("archiving session");
+		
+		try {
+			session.setId(XnatExperimentdata.CreateNewID());
+		} catch (Exception e) {
+			throw new ArchivingException("unable to create new session ID", e);
+		}
+
+		try {
+			final ValidationResults validation = session.validate();
+			if (null != validation && !validation.isValid()) {
+				throw new ValidationException(validation);
+			}
+		} catch (ArchivingException e) {
+			throw e;
+		} catch (Exception e) {
+			failed("unable to perform session validation: " + e.getMessage());
+			throw new ArchivingException("unable to perform session validation", e);
+		}
+		
+		preventConcurrentArchiving();
+		fixScans(arcSessionDir);
+				
+		// save the session to the database
+		try {
+			if (session.save(user, false, true)) {
+				user.clearLocalCache();
+				MaterializedView.DeleteByUser(user);
+			    
+				if (this.shouldForceQuarantine) {
+					session.quarantine(user);
+				} else {
+					final XnatProjectdata proj = session.getPrimaryProject(false);
+					if (null != proj.getArcSpecification().getQuarantineCode() &&
+							proj.getArcSpecification().getQuarantineCode().equals(1)) {
+						session.quarantine(user);
+					}
+				}				
+			}
+		} catch (Exception e) {
+			logger.error("unable to commit session to database", e);
+			failed("error committing session to database: " + e.getMessage());
+			throw new ArchivingException("unable to commit session to database", e);
+		}
+		
+		final String prearcSessionPath = session.getPrearchivepath();
+		updatePrearchiveSessionXML(prearcSessionPath);
+		final boolean successful = doTransfer(prearcSessionPath);
+		// TODO: what about schema element manipulation?
+		// TODO: what about project scoping line?
+
+		if (successful) {
+			final StringBuilder urlb = new StringBuilder(TurbineUtils.GetFullServerPath());
+			urlb.append("/REST/projects/").append(project);
+			urlb.append("/subjects/").append(session.getSubjectId());
+			urlb.append("/experiments/").append(session.getLabel());
+			try {
+				final URL url = new URL(urlb.toString());
+				completed("archiving operation complete");
+				return url;
+			} catch (MalformedURLException e) {
+				throw new RuntimeException("invalid session URL", e);
+			}
+		} else {
+			failed("archiving operation failed");
+			throw new ArchivingException("archiving operation failed");
+		}
+	}
+
+
+	/**
+	 * Releases any resources held by the archiver.
+	 */
+	public void dispose() {
+		listeners.clear();
+	}
+}

plugin-resources/webapp/xnat/java/org/nrg/xnat/archive/ValidationException.java

+/**
+ * Copyright 2010 Washington University
+ */
+package org.nrg.xnat.archive;
+
+import java.util.Arrays;
+
+import org.nrg.xft.utils.ValidationUtils.ValidationResults;
+import org.restlet.data.Status;
+
+/**
+ * Indicates that a validation has failed.
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public class ValidationException extends ArchivingException {
+	private static final long serialVersionUID = 1L;
+	private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+	private static final Status status = Status.SERVER_ERROR_INTERNAL;
+	private final ValidationResults results;
+	
+	/**
+	 * @param results cause of the ValidationException: must not be valid
+	 */
+	public ValidationException(final ValidationResults results) {
+		super(status, makeMessage(results));
+		if (results.isValid()) {
+			throw new IllegalArgumentException("validation must have failed");
+		}
+		this.results = results;
+	}
+	
+	/**
+	 * Retrieves the ValidationResults underlying this exception.
+	 * @return ValidationResults
+	 */
+	public ValidationResults getValidationResults() {
+		return results;
+	}
+