5093 |
14 Nov 18 |
olle |
1 |
package net.sf.basedb.meludi.dao; |
5093 |
14 Nov 18 |
olle |
2 |
|
5093 |
14 Nov 18 |
olle |
3 |
import java.util.ArrayList; |
5093 |
14 Nov 18 |
olle |
4 |
import java.util.List; |
5093 |
14 Nov 18 |
olle |
5 |
|
5093 |
14 Nov 18 |
olle |
6 |
import org.json.simple.JSONObject; |
5093 |
14 Nov 18 |
olle |
7 |
|
5093 |
14 Nov 18 |
olle |
8 |
import net.sf.basedb.core.AnnotationSimpleRestriction; |
5093 |
14 Nov 18 |
olle |
9 |
import net.sf.basedb.core.AnnotationType; |
5093 |
14 Nov 18 |
olle |
10 |
import net.sf.basedb.core.DbControl; |
5093 |
14 Nov 18 |
olle |
11 |
import net.sf.basedb.core.ItemQuery; |
5093 |
14 Nov 18 |
olle |
12 |
import net.sf.basedb.core.Operator; |
5093 |
14 Nov 18 |
olle |
13 |
import net.sf.basedb.core.Sample; |
5093 |
14 Nov 18 |
olle |
14 |
import net.sf.basedb.core.Type; |
5093 |
14 Nov 18 |
olle |
15 |
import net.sf.basedb.core.query.Expressions; |
5093 |
14 Nov 18 |
olle |
16 |
import net.sf.basedb.core.query.Hql; |
5093 |
14 Nov 18 |
olle |
17 |
import net.sf.basedb.core.query.Orders; |
5093 |
14 Nov 18 |
olle |
18 |
import net.sf.basedb.core.query.Restrictions; |
5093 |
14 Nov 18 |
olle |
19 |
import net.sf.basedb.meludi.JsonUtil; |
5093 |
14 Nov 18 |
olle |
20 |
import net.sf.basedb.meludi.Meludi; |
5093 |
14 Nov 18 |
olle |
21 |
|
5093 |
14 Nov 18 |
olle |
22 |
/** |
5093 |
14 Nov 18 |
olle |
Class for loading information that is related to Histology samples. |
5093 |
14 Nov 18 |
olle |
24 |
|
5093 |
14 Nov 18 |
olle |
@author nicklas |
5093 |
14 Nov 18 |
olle |
@since 2.7 |
5093 |
14 Nov 18 |
olle |
27 |
*/ |
5093 |
14 Nov 18 |
olle |
28 |
public class Histology |
5093 |
14 Nov 18 |
olle |
29 |
extends MeludiItem<Sample> |
5093 |
14 Nov 18 |
olle |
30 |
{ |
5093 |
14 Nov 18 |
olle |
31 |
|
5093 |
14 Nov 18 |
olle |
32 |
/** |
5093 |
14 Nov 18 |
olle |
This ID is used on Histology work lists for the external ID attribute. |
5093 |
14 Nov 18 |
olle |
34 |
*/ |
5093 |
14 Nov 18 |
olle |
35 |
public static final String WORK_LIST_ID = "net.sf.basedb.meludi.histology.work-list"; |
5093 |
14 Nov 18 |
olle |
36 |
|
5093 |
14 Nov 18 |
olle |
37 |
/** |
5093 |
14 Nov 18 |
olle |
Flag value for the {@link Annotationtype#FLAG} annotation when a Histology item has failed |
5093 |
14 Nov 18 |
olle |
to get a GoodStain. |
5093 |
14 Nov 18 |
olle |
@since 2.15 |
5093 |
14 Nov 18 |
olle |
41 |
*/ |
5093 |
14 Nov 18 |
olle |
42 |
public static final String FLAG_NO_GOOD_STAIN = "NoGoodStain"; |
5093 |
14 Nov 18 |
olle |
43 |
|
5093 |
14 Nov 18 |
olle |
44 |
/** |
5093 |
14 Nov 18 |
olle |
The number of samples per paraffin block. |
5093 |
14 Nov 18 |
olle |
46 |
*/ |
5093 |
14 Nov 18 |
olle |
47 |
public static final int SAMPLES_PER_BLOCK = 5; |
5093 |
14 Nov 18 |
olle |
48 |
|
5093 |
14 Nov 18 |
olle |
49 |
/** |
5093 |
14 Nov 18 |
olle |
Path on BASE file system to histology images. |
5093 |
14 Nov 18 |
olle |
@since 3.6 |
5093 |
14 Nov 18 |
olle |
52 |
*/ |
5093 |
14 Nov 18 |
olle |
//public static final String IMAGE_DIR = "/home/SCANB/HistologyImages"; |
5093 |
14 Nov 18 |
olle |
54 |
public static final String IMAGE_DIR = "/home/HistologyImages"; |
5093 |
14 Nov 18 |
olle |
55 |
|
5093 |
14 Nov 18 |
olle |
56 |
|
5093 |
14 Nov 18 |
olle |
57 |
/** |
5093 |
14 Nov 18 |
olle |
Get the folder for storing image for the given sample name. |
5093 |
14 Nov 18 |
olle |
59 |
|
5093 |
14 Nov 18 |
olle |
We want to use a prefix in the BASE file system to prevent |
5093 |
14 Nov 18 |
olle |
several thousands of subfolders or files inside a single folder. |
5093 |
14 Nov 18 |
olle |
The prefix should only be used if the name folder starts with |
5093 |
14 Nov 18 |
olle |
digits. The first level is the first two digits and the second level is |
5093 |
14 Nov 18 |
olle |
the first four digits. |
5093 |
14 Nov 18 |
olle |
65 |
|
5093 |
14 Nov 18 |
olle |
66 |
|
5093 |
14 Nov 18 |
olle |
Examples: |
5093 |
14 Nov 18 |
olle |
1234567.1.his.he1 --> /12/1234/ |
5093 |
14 Nov 18 |
olle |
@since 3.6 |
5093 |
14 Nov 18 |
olle |
70 |
*/ |
5093 |
14 Nov 18 |
olle |
71 |
public static String getImageFolder(String name) |
5093 |
14 Nov 18 |
olle |
72 |
{ |
5093 |
14 Nov 18 |
olle |
// If the name starts with 7 digits+'.'+at least one more digit |
5093 |
14 Nov 18 |
olle |
// insert prefix based on first 2+4 digits |
5093 |
14 Nov 18 |
olle |
75 |
return name.replaceFirst("^((\\d{2})\\d{2})\\d{3}\\.\\d+.*", "/$2/$1/"); |
5093 |
14 Nov 18 |
olle |
76 |
} |
5093 |
14 Nov 18 |
olle |
77 |
|
5093 |
14 Nov 18 |
olle |
78 |
|
5093 |
14 Nov 18 |
olle |
79 |
/** |
5093 |
14 Nov 18 |
olle |
Find Histology samples that have not yet been embedded in paraffin blocks. |
5093 |
14 Nov 18 |
olle |
The query will look for samples with the {@link Subtype#HISTOLOGY} subtype |
5093 |
14 Nov 18 |
olle |
that has no 'created' date. Since the Histology items are currently stored |
5093 |
14 Nov 18 |
olle |
in temporary boxes, the list is sorted by bioplate and position. |
5093 |
14 Nov 18 |
olle |
@param excludeWorkLists TRUE to exclude Histology items that have been picked and saved in a work list |
5093 |
14 Nov 18 |
olle |
85 |
*/ |
5093 |
14 Nov 18 |
olle |
86 |
public static List<Histology> findUnembeddedHistologyItems(DbControl dc, boolean excludeWorkLists, int maxResults) |
5093 |
14 Nov 18 |
olle |
87 |
{ |
5093 |
14 Nov 18 |
olle |
88 |
List<Histology> histology = new ArrayList<Histology>(); |
5093 |
14 Nov 18 |
olle |
89 |
|
5093 |
14 Nov 18 |
olle |
// Create a query that load all Histology samples without created date |
5093 |
14 Nov 18 |
olle |
91 |
ItemQuery<Sample> query = Sample.getQuery(); |
5093 |
14 Nov 18 |
olle |
92 |
query.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT); |
5093 |
14 Nov 18 |
olle |
// Filter on Lysate subtype |
5093 |
14 Nov 18 |
olle |
94 |
Subtype.HISTOLOGY.addFilter(dc, query); |
5093 |
14 Nov 18 |
olle |
// Filter on created date == null |
5093 |
14 Nov 18 |
olle |
96 |
query.restrict(Restrictions.eq(Hql.property("ce", "eventDate"), null)); |
5093 |
14 Nov 18 |
olle |
// Filter on not present in a work list |
5093 |
14 Nov 18 |
olle |
98 |
if (excludeWorkLists) |
5093 |
14 Nov 18 |
olle |
99 |
{ |
5093 |
14 Nov 18 |
olle |
100 |
ItemQuery<Sample> workQuery = Sample.getQuery(); |
5093 |
14 Nov 18 |
olle |
101 |
workQuery.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT); |
5093 |
14 Nov 18 |
olle |
102 |
String subquery = "select mmb from ItemListData lst INNER JOIN lst.members mmb where lst.externalId=:externalId and lst.removed=false"; |
5093 |
14 Nov 18 |
olle |
103 |
workQuery.restrict(Hql.restriction("$id NOT IN ("+subquery+")", "$")); |
5093 |
14 Nov 18 |
olle |
104 |
workQuery.setParameter("externalId", WORK_LIST_ID, Type.STRING); |
5093 |
14 Nov 18 |
olle |
105 |
} |
5093 |
14 Nov 18 |
olle |
106 |
|
5093 |
14 Nov 18 |
olle |
// Join the creation event and bioplate |
5093 |
14 Nov 18 |
olle |
108 |
query.join(Hql.innerJoin(null, "creationEvent", "ce", true)); |
5093 |
14 Nov 18 |
olle |
109 |
query.join(Hql.leftJoin(null, "bioWell", "bw", null, true)); |
5093 |
14 Nov 18 |
olle |
110 |
query.join(Hql.leftJoin("bw", "bioPlate", "bp", null, true)); |
5093 |
14 Nov 18 |
olle |
111 |
|
5093 |
14 Nov 18 |
olle |
// Sort by bioplate position -- those without plate are sorted last by id |
5093 |
14 Nov 18 |
olle |
113 |
query.order(Orders.asc(Hql.expression("coalesce(bp.name, 'zzzz')", null))); |
5093 |
14 Nov 18 |
olle |
114 |
query.order(Orders.asc(Hql.property("bw", "row"))); |
5093 |
14 Nov 18 |
olle |
115 |
query.order(Orders.asc(Hql.property("bw", "column"))); |
5093 |
14 Nov 18 |
olle |
116 |
query.order(Orders.asc(Hql.property("id"))); |
5093 |
14 Nov 18 |
olle |
117 |
|
5093 |
14 Nov 18 |
olle |
118 |
query.setMaxResults(maxResults); |
5093 |
14 Nov 18 |
olle |
119 |
|
5093 |
14 Nov 18 |
olle |
120 |
List<Sample> samples = query.list(dc); |
5093 |
14 Nov 18 |
olle |
121 |
for (Sample s : samples) |
5093 |
14 Nov 18 |
olle |
122 |
{ |
5093 |
14 Nov 18 |
olle |
123 |
histology.add(new Histology(s)); |
5093 |
14 Nov 18 |
olle |
124 |
} |
5093 |
14 Nov 18 |
olle |
125 |
return histology; |
5093 |
14 Nov 18 |
olle |
126 |
} |
5093 |
14 Nov 18 |
olle |
127 |
|
5848 |
02 Mar 20 |
olle |
128 |
|
5093 |
14 Nov 18 |
olle |
129 |
/** |
5848 |
02 Mar 20 |
olle |
Find all histology items by name. This method will check for {@link Subtype#HISTOLOGY} samples |
5848 |
02 Mar 20 |
olle |
with a specific name (eg. xxx.his). |
5848 |
02 Mar 20 |
olle |
@since 2.11 |
5848 |
02 Mar 20 |
olle |
133 |
*/ |
5848 |
02 Mar 20 |
olle |
134 |
public static List<Histology> findByName(DbControl dc, String name) |
5848 |
02 Mar 20 |
olle |
135 |
{ |
5848 |
02 Mar 20 |
olle |
136 |
ItemQuery<Sample> histologyQuery = Sample.getQuery(); |
5848 |
02 Mar 20 |
olle |
137 |
Subtype.HISTOLOGY.addFilter(dc, histologyQuery); |
5848 |
02 Mar 20 |
olle |
138 |
histologyQuery.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT); |
5848 |
02 Mar 20 |
olle |
//histologyQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.parameter("name", name+".%", Type.STRING))); |
5848 |
02 Mar 20 |
olle |
140 |
histologyQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.parameter("name", name+"%", Type.STRING))); |
5848 |
02 Mar 20 |
olle |
141 |
histologyQuery.order(Orders.asc(Hql.property("name"))); |
5848 |
02 Mar 20 |
olle |
142 |
|
5848 |
02 Mar 20 |
olle |
143 |
List<Sample> tmp = histologyQuery.list(dc); |
5848 |
02 Mar 20 |
olle |
144 |
List<Histology> histology = new ArrayList<Histology>(tmp.size()); |
5848 |
02 Mar 20 |
olle |
145 |
for (Sample s : tmp) |
5848 |
02 Mar 20 |
olle |
146 |
{ |
5848 |
02 Mar 20 |
olle |
147 |
histology.add(new Histology(s)); |
5848 |
02 Mar 20 |
olle |
148 |
} |
5848 |
02 Mar 20 |
olle |
149 |
return histology; |
5848 |
02 Mar 20 |
olle |
150 |
} |
5848 |
02 Mar 20 |
olle |
151 |
|
5848 |
02 Mar 20 |
olle |
152 |
|
5848 |
02 Mar 20 |
olle |
153 |
/** |
5093 |
14 Nov 18 |
olle |
Find all histology items by case name. This method will check for {@link Subtype#HISTOLOGY} samples |
5093 |
14 Nov 18 |
olle |
with a name matching the case name (eg. xxx.his). |
5093 |
14 Nov 18 |
olle |
@since 2.11 |
5093 |
14 Nov 18 |
olle |
157 |
*/ |
5093 |
14 Nov 18 |
olle |
158 |
public static List<Histology> findByCaseName(DbControl dc, String name) |
5093 |
14 Nov 18 |
olle |
159 |
{ |
5093 |
14 Nov 18 |
olle |
160 |
/* |
5093 |
14 Nov 18 |
olle |
// Get rid of suffixes in the name (eg. 'C' which is used for pre-neoadjuvant forms) |
5093 |
14 Nov 18 |
olle |
if (name.length() > 7) name = name.substring(0, 7); |
5093 |
14 Nov 18 |
olle |
163 |
|
5093 |
14 Nov 18 |
olle |
// Look for a blood case with the given name |
5093 |
14 Nov 18 |
olle |
ItemQuery<Sample> histologyQuery = Sample.getQuery(); |
5093 |
14 Nov 18 |
olle |
Subtype.HISTOLOGY.addFilter(dc, histologyQuery); |
5093 |
14 Nov 18 |
olle |
histologyQuery.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT); |
5093 |
14 Nov 18 |
olle |
histologyQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.parameter("name", name+".%", Type.STRING))); |
5093 |
14 Nov 18 |
olle |
histologyQuery.order(Orders.asc(Hql.property("name"))); |
5093 |
14 Nov 18 |
olle |
170 |
|
5093 |
14 Nov 18 |
olle |
List<Sample> tmp = histologyQuery.list(dc); |
5093 |
14 Nov 18 |
olle |
List<Histology> histology = new ArrayList<Histology>(tmp.size()); |
5093 |
14 Nov 18 |
olle |
for (Sample s : tmp) |
5093 |
14 Nov 18 |
olle |
174 |
{ |
5093 |
14 Nov 18 |
olle |
histology.add(new Histology(s)); |
5093 |
14 Nov 18 |
olle |
176 |
} |
5093 |
14 Nov 18 |
olle |
return histology; |
5093 |
14 Nov 18 |
olle |
178 |
*/ |
5093 |
14 Nov 18 |
olle |
// Look for a histology item with the given case ID as annotation. |
5093 |
14 Nov 18 |
olle |
180 |
String caseId = name; |
5093 |
14 Nov 18 |
olle |
181 |
AnnotationType caseIdType = Annotationtype.CASE_ID.load(dc); |
5093 |
14 Nov 18 |
olle |
182 |
ItemQuery<Sample> histologyQuery = Sample.getQuery(); |
5093 |
14 Nov 18 |
olle |
183 |
Subtype.HISTOLOGY.addFilter(dc, histologyQuery); |
5093 |
14 Nov 18 |
olle |
184 |
histologyQuery.restrict(new AnnotationSimpleRestriction(null, caseIdType, Operator.EQ, caseId, true, false)); |
5093 |
14 Nov 18 |
olle |
185 |
histologyQuery.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT); |
5093 |
14 Nov 18 |
olle |
186 |
histologyQuery.order(Orders.asc(Hql.property("name"))); |
5093 |
14 Nov 18 |
olle |
187 |
|
5093 |
14 Nov 18 |
olle |
188 |
List<Sample> tmp = histologyQuery.list(dc); |
5093 |
14 Nov 18 |
olle |
189 |
List<Histology> histologyList = new ArrayList<Histology>(tmp.size()); |
5093 |
14 Nov 18 |
olle |
190 |
for (Sample s : tmp) |
5093 |
14 Nov 18 |
olle |
191 |
{ |
5093 |
14 Nov 18 |
olle |
192 |
histologyList.add(new Histology(s)); |
5093 |
14 Nov 18 |
olle |
193 |
} |
5093 |
14 Nov 18 |
olle |
194 |
return histologyList; |
5093 |
14 Nov 18 |
olle |
195 |
} |
5093 |
14 Nov 18 |
olle |
196 |
|
5093 |
14 Nov 18 |
olle |
197 |
|
5093 |
14 Nov 18 |
olle |
198 |
/** |
5093 |
14 Nov 18 |
olle |
Get a Histology when the id is known. |
5093 |
14 Nov 18 |
olle |
200 |
*/ |
5093 |
14 Nov 18 |
olle |
201 |
public static Histology getById(DbControl dc, int id) |
5093 |
14 Nov 18 |
olle |
202 |
{ |
5093 |
14 Nov 18 |
olle |
203 |
return new Histology(Sample.getById(dc, id)); |
5093 |
14 Nov 18 |
olle |
204 |
} |
5093 |
14 Nov 18 |
olle |
205 |
|
5093 |
14 Nov 18 |
olle |
206 |
|
5093 |
14 Nov 18 |
olle |
207 |
private JSONObject jsonWell; |
5093 |
14 Nov 18 |
olle |
208 |
|
5093 |
14 Nov 18 |
olle |
209 |
private Histology(Sample sample) |
5093 |
14 Nov 18 |
olle |
210 |
{ |
5093 |
14 Nov 18 |
olle |
211 |
super(sample); |
5093 |
14 Nov 18 |
olle |
212 |
|
5093 |
14 Nov 18 |
olle |
213 |
} |
5093 |
14 Nov 18 |
olle |
214 |
|
5093 |
14 Nov 18 |
olle |
215 |
|
5093 |
14 Nov 18 |
olle |
216 |
/** |
5093 |
14 Nov 18 |
olle |
Get the real sample that represents this Histology item in BASE. |
5093 |
14 Nov 18 |
olle |
218 |
*/ |
5093 |
14 Nov 18 |
olle |
219 |
public Sample getSample() |
5093 |
14 Nov 18 |
olle |
220 |
{ |
5093 |
14 Nov 18 |
olle |
221 |
return getItem(); |
5093 |
14 Nov 18 |
olle |
222 |
} |
5093 |
14 Nov 18 |
olle |
223 |
|
5093 |
14 Nov 18 |
olle |
224 |
@SuppressWarnings("unchecked") |
5093 |
14 Nov 18 |
olle |
225 |
@Override |
5093 |
14 Nov 18 |
olle |
226 |
protected void initJSON(JSONObject json) |
5093 |
14 Nov 18 |
olle |
227 |
{ |
5093 |
14 Nov 18 |
olle |
228 |
super.initJSON(json); |
5093 |
14 Nov 18 |
olle |
229 |
if (jsonWell != null) json.put("bioWell", jsonWell); |
5093 |
14 Nov 18 |
olle |
230 |
|
5093 |
14 Nov 18 |
olle |
231 |
} |
5093 |
14 Nov 18 |
olle |
232 |
|
5093 |
14 Nov 18 |
olle |
233 |
/** |
5093 |
14 Nov 18 |
olle |
Load information about the plate and location the current RNA |
5093 |
14 Nov 18 |
olle |
is located on. |
5093 |
14 Nov 18 |
olle |
236 |
*/ |
5093 |
14 Nov 18 |
olle |
237 |
public JSONObject loadBioPlateLocation() |
5093 |
14 Nov 18 |
olle |
238 |
{ |
5093 |
14 Nov 18 |
olle |
239 |
if (jsonWell == null) |
5093 |
14 Nov 18 |
olle |
240 |
{ |
5093 |
14 Nov 18 |
olle |
241 |
jsonWell = JsonUtil.getBioWellAsJSON(getItem().getBioWell(), true); |
5093 |
14 Nov 18 |
olle |
242 |
} |
5093 |
14 Nov 18 |
olle |
243 |
return jsonWell; |
5093 |
14 Nov 18 |
olle |
244 |
} |
5093 |
14 Nov 18 |
olle |
245 |
|
5093 |
14 Nov 18 |
olle |
246 |
|
5093 |
14 Nov 18 |
olle |
247 |
} |