1669 |
29 May 12 |
nicklas |
1 |
package net.sf.basedb.reggie.dao; |
1669 |
29 May 12 |
nicklas |
2 |
|
1669 |
29 May 12 |
nicklas |
3 |
import java.util.ArrayList; |
1669 |
29 May 12 |
nicklas |
4 |
import java.util.List; |
1669 |
29 May 12 |
nicklas |
5 |
|
1669 |
29 May 12 |
nicklas |
6 |
import org.json.simple.JSONObject; |
1669 |
29 May 12 |
nicklas |
7 |
|
1669 |
29 May 12 |
nicklas |
8 |
import net.sf.basedb.core.DbControl; |
1669 |
29 May 12 |
nicklas |
9 |
import net.sf.basedb.core.ItemQuery; |
1669 |
29 May 12 |
nicklas |
10 |
import net.sf.basedb.core.Sample; |
1826 |
07 Feb 13 |
nicklas |
11 |
import net.sf.basedb.core.Type; |
1681 |
01 Jun 12 |
nicklas |
12 |
import net.sf.basedb.core.query.Expressions; |
1669 |
29 May 12 |
nicklas |
13 |
import net.sf.basedb.core.query.Hql; |
1669 |
29 May 12 |
nicklas |
14 |
import net.sf.basedb.core.query.Orders; |
1669 |
29 May 12 |
nicklas |
15 |
import net.sf.basedb.core.query.Restrictions; |
1826 |
07 Feb 13 |
nicklas |
16 |
import net.sf.basedb.reggie.JsonUtil; |
1669 |
29 May 12 |
nicklas |
17 |
import net.sf.basedb.reggie.Reggie; |
1669 |
29 May 12 |
nicklas |
18 |
|
1669 |
29 May 12 |
nicklas |
19 |
/** |
1669 |
29 May 12 |
nicklas |
Class for loading information that is related to Histology samples. |
1669 |
29 May 12 |
nicklas |
21 |
|
1669 |
29 May 12 |
nicklas |
@author nicklas |
1669 |
29 May 12 |
nicklas |
@since 2.7 |
1669 |
29 May 12 |
nicklas |
24 |
*/ |
1669 |
29 May 12 |
nicklas |
25 |
public class Histology |
1669 |
29 May 12 |
nicklas |
26 |
extends ReggieItem<Sample> |
1669 |
29 May 12 |
nicklas |
27 |
{ |
1669 |
29 May 12 |
nicklas |
28 |
|
1681 |
01 Jun 12 |
nicklas |
29 |
/** |
2190 |
13 Jan 14 |
nicklas |
This ID is used on Histology work lists for the external ID attribute. |
1681 |
01 Jun 12 |
nicklas |
31 |
*/ |
2190 |
13 Jan 14 |
nicklas |
32 |
public static final String WORK_LIST_ID = "net.sf.basedb.reggie.histology.work-list"; |
2190 |
13 Jan 14 |
nicklas |
33 |
|
1669 |
29 May 12 |
nicklas |
34 |
/** |
2242 |
21 Feb 14 |
nicklas |
Flag value for the {@link Annotationtype#FLAG} annotation when a Histology item has failed |
2242 |
21 Feb 14 |
nicklas |
to get a GoodStain. |
2242 |
21 Feb 14 |
nicklas |
@since 2.15 |
2242 |
21 Feb 14 |
nicklas |
38 |
*/ |
2242 |
21 Feb 14 |
nicklas |
39 |
public static final String FLAG_NO_GOOD_STAIN = "NoGoodStain"; |
2190 |
13 Jan 14 |
nicklas |
40 |
|
2190 |
13 Jan 14 |
nicklas |
41 |
/** |
1692 |
08 Jun 12 |
nicklas |
The number of samples per paraffin block. |
1692 |
08 Jun 12 |
nicklas |
43 |
*/ |
1692 |
08 Jun 12 |
nicklas |
44 |
public static final int SAMPLES_PER_BLOCK = 5; |
1692 |
08 Jun 12 |
nicklas |
45 |
|
1692 |
08 Jun 12 |
nicklas |
46 |
/** |
3368 |
08 Jun 15 |
nicklas |
Path on BASE file system to histology images. |
3368 |
08 Jun 15 |
nicklas |
@since 3.6 |
3368 |
08 Jun 15 |
nicklas |
49 |
*/ |
3368 |
08 Jun 15 |
nicklas |
50 |
public static final String IMAGE_DIR = "/home/SCANB/HistologyImages"; |
5784 |
12 Dec 19 |
nicklas |
51 |
|
5784 |
12 Dec 19 |
nicklas |
52 |
/** |
5784 |
12 Dec 19 |
nicklas |
Path on BASE file system to histology images for external specimen. |
5784 |
12 Dec 19 |
nicklas |
@since 4.25 |
5784 |
12 Dec 19 |
nicklas |
55 |
*/ |
5784 |
12 Dec 19 |
nicklas |
56 |
public static final String EXTERNAL_IMAGE_DIR = "/home/External/HistologyImages"; |
5784 |
12 Dec 19 |
nicklas |
57 |
|
3368 |
08 Jun 15 |
nicklas |
58 |
|
3368 |
08 Jun 15 |
nicklas |
59 |
/** |
3368 |
08 Jun 15 |
nicklas |
Get the folder for storing image for the given sample name. |
3368 |
08 Jun 15 |
nicklas |
61 |
|
3368 |
08 Jun 15 |
nicklas |
We want to use a prefix in the BASE file system to prevent |
3368 |
08 Jun 15 |
nicklas |
several thousands of subfolders or files inside a single folder. |
3368 |
08 Jun 15 |
nicklas |
The prefix should only be used if the name folder starts with |
3368 |
08 Jun 15 |
nicklas |
digits. The first level is the first two digits and the second level is |
3368 |
08 Jun 15 |
nicklas |
the first four digits. |
3368 |
08 Jun 15 |
nicklas |
67 |
|
5784 |
12 Dec 19 |
nicklas |
For external items the prefix is the taken from the characters before |
5784 |
12 Dec 19 |
nicklas |
the first underscore (_). |
3368 |
08 Jun 15 |
nicklas |
70 |
|
3368 |
08 Jun 15 |
nicklas |
Examples: |
5784 |
12 Dec 19 |
nicklas |
1234567.1.his.he1 --> {IMAGE_DIR}/12/1234/ |
5784 |
12 Dec 19 |
nicklas |
NN_External.his.he1 --> {EXTERNAL_IMAGE_DIR}/NN/ |
5784 |
12 Dec 19 |
nicklas |
74 |
|
5784 |
12 Dec 19 |
nicklas |
@since 3.6, 4.25 |
3368 |
08 Jun 15 |
nicklas |
76 |
*/ |
3368 |
08 Jun 15 |
nicklas |
77 |
public static String getImageFolder(String name) |
3368 |
08 Jun 15 |
nicklas |
78 |
{ |
5784 |
12 Dec 19 |
nicklas |
79 |
if (Reggie.isExternalItem(name)) |
5784 |
12 Dec 19 |
nicklas |
80 |
{ |
5784 |
12 Dec 19 |
nicklas |
// Get characters before first _ |
5784 |
12 Dec 19 |
nicklas |
82 |
return Histology.EXTERNAL_IMAGE_DIR + name.replaceFirst("^(.+?)_.*", "/$1/"); |
5784 |
12 Dec 19 |
nicklas |
83 |
} |
5784 |
12 Dec 19 |
nicklas |
84 |
else |
5784 |
12 Dec 19 |
nicklas |
85 |
{ |
5784 |
12 Dec 19 |
nicklas |
// If the name starts with 7 digits+'.'+at least one more digit |
5784 |
12 Dec 19 |
nicklas |
// insert prefix based on first 2+4 digits |
5784 |
12 Dec 19 |
nicklas |
88 |
return Histology.IMAGE_DIR + name.replaceFirst("^((\\d{2})\\d{2})\\d{3}\\.\\d+.*", "/$2/$1/"); |
5784 |
12 Dec 19 |
nicklas |
89 |
} |
3368 |
08 Jun 15 |
nicklas |
90 |
} |
3368 |
08 Jun 15 |
nicklas |
91 |
|
3368 |
08 Jun 15 |
nicklas |
92 |
|
3368 |
08 Jun 15 |
nicklas |
93 |
/** |
1669 |
29 May 12 |
nicklas |
Find Histology samples that have not yet been embedded in paraffin blocks. |
1669 |
29 May 12 |
nicklas |
The query will look for samples with the {@link Subtype#HISTOLOGY} subtype |
1669 |
29 May 12 |
nicklas |
that has no 'created' date. Since the Histology items are currently stored |
1669 |
29 May 12 |
nicklas |
in temporary boxes, the list is sorted by bioplate and position. |
1681 |
01 Jun 12 |
nicklas |
@param excludeWorkLists TRUE to exclude Histology items that have been picked and saved in a work list |
1669 |
29 May 12 |
nicklas |
99 |
*/ |
1681 |
01 Jun 12 |
nicklas |
100 |
public static List<Histology> findUnembeddedHistologyItems(DbControl dc, boolean excludeWorkLists, int maxResults) |
1669 |
29 May 12 |
nicklas |
101 |
{ |
1669 |
29 May 12 |
nicklas |
102 |
List<Histology> histology = new ArrayList<Histology>(); |
1669 |
29 May 12 |
nicklas |
103 |
|
1669 |
29 May 12 |
nicklas |
// Create a query that load all Histology samples without created date |
1669 |
29 May 12 |
nicklas |
105 |
ItemQuery<Sample> query = Sample.getQuery(); |
1669 |
29 May 12 |
nicklas |
106 |
query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
1669 |
29 May 12 |
nicklas |
// Filter on Lysate subtype |
1669 |
29 May 12 |
nicklas |
108 |
Subtype.HISTOLOGY.addFilter(dc, query); |
1669 |
29 May 12 |
nicklas |
// Filter on created date == null |
1669 |
29 May 12 |
nicklas |
110 |
query.restrict(Restrictions.eq(Hql.property("ce", "eventDate"), null)); |
1681 |
01 Jun 12 |
nicklas |
// Filter on not present in a work list |
1681 |
01 Jun 12 |
nicklas |
112 |
if (excludeWorkLists) |
1681 |
01 Jun 12 |
nicklas |
113 |
{ |
1681 |
01 Jun 12 |
nicklas |
114 |
ItemQuery<Sample> workQuery = Sample.getQuery(); |
1681 |
01 Jun 12 |
nicklas |
115 |
workQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
3342 |
19 May 15 |
nicklas |
116 |
String subquery = "select mmb from ItemListData lst INNER JOIN lst.members mmb where lst.externalId=:externalId and lst.removed=false"; |
3342 |
19 May 15 |
nicklas |
117 |
workQuery.restrict(Hql.restriction("$id NOT IN ("+subquery+")", "$")); |
3342 |
19 May 15 |
nicklas |
118 |
workQuery.setParameter("externalId", WORK_LIST_ID, Type.STRING); |
1681 |
01 Jun 12 |
nicklas |
119 |
} |
1669 |
29 May 12 |
nicklas |
120 |
|
1669 |
29 May 12 |
nicklas |
// Join the creation event and bioplate |
1681 |
01 Jun 12 |
nicklas |
122 |
query.join(Hql.innerJoin(null, "creationEvent", "ce", true)); |
1669 |
29 May 12 |
nicklas |
123 |
query.join(Hql.leftJoin(null, "bioWell", "bw", null, true)); |
1669 |
29 May 12 |
nicklas |
124 |
query.join(Hql.leftJoin("bw", "bioPlate", "bp", null, true)); |
1669 |
29 May 12 |
nicklas |
125 |
|
1682 |
01 Jun 12 |
nicklas |
// Sort by bioplate position -- those without plate are sorted last by id |
1682 |
01 Jun 12 |
nicklas |
127 |
query.order(Orders.asc(Hql.expression("coalesce(bp.name, 'zzzz')", null))); |
1669 |
29 May 12 |
nicklas |
128 |
query.order(Orders.asc(Hql.property("bw", "row"))); |
1669 |
29 May 12 |
nicklas |
129 |
query.order(Orders.asc(Hql.property("bw", "column"))); |
1669 |
29 May 12 |
nicklas |
130 |
query.order(Orders.asc(Hql.property("id"))); |
1669 |
29 May 12 |
nicklas |
131 |
|
1669 |
29 May 12 |
nicklas |
132 |
query.setMaxResults(maxResults); |
1669 |
29 May 12 |
nicklas |
133 |
|
1669 |
29 May 12 |
nicklas |
134 |
List<Sample> samples = query.list(dc); |
1669 |
29 May 12 |
nicklas |
135 |
for (Sample s : samples) |
1669 |
29 May 12 |
nicklas |
136 |
{ |
1669 |
29 May 12 |
nicklas |
137 |
histology.add(new Histology(s)); |
1669 |
29 May 12 |
nicklas |
138 |
} |
1669 |
29 May 12 |
nicklas |
139 |
return histology; |
1669 |
29 May 12 |
nicklas |
140 |
} |
1669 |
29 May 12 |
nicklas |
141 |
|
1669 |
29 May 12 |
nicklas |
142 |
/** |
1826 |
07 Feb 13 |
nicklas |
Find all histology items by case name. This method will check for {@link Subtype#HISTOLOGY} samples |
1826 |
07 Feb 13 |
nicklas |
with a name matching the case name (eg. xxx.his). |
1826 |
07 Feb 13 |
nicklas |
@since 2.11 |
1826 |
07 Feb 13 |
nicklas |
146 |
*/ |
1826 |
07 Feb 13 |
nicklas |
147 |
public static List<Histology> findByCaseName(DbControl dc, String name) |
1831 |
08 Feb 13 |
nicklas |
148 |
{ |
1826 |
07 Feb 13 |
nicklas |
// Get rid of suffixes in the name (eg. 'C' which is used for pre-neoadjuvant forms) |
1826 |
07 Feb 13 |
nicklas |
150 |
if (name.length() > 7) name = name.substring(0, 7); |
1826 |
07 Feb 13 |
nicklas |
151 |
|
1826 |
07 Feb 13 |
nicklas |
// Look for a blood case with the given name |
1826 |
07 Feb 13 |
nicklas |
153 |
ItemQuery<Sample> histologyQuery = Sample.getQuery(); |
1826 |
07 Feb 13 |
nicklas |
154 |
Subtype.HISTOLOGY.addFilter(dc, histologyQuery); |
2917 |
11 Nov 14 |
nicklas |
155 |
histologyQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT); |
1831 |
08 Feb 13 |
nicklas |
156 |
histologyQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.parameter("name", name+".%", Type.STRING))); |
2917 |
11 Nov 14 |
nicklas |
157 |
histologyQuery.order(Orders.asc(Hql.property("name"))); |
2917 |
11 Nov 14 |
nicklas |
158 |
|
1826 |
07 Feb 13 |
nicklas |
159 |
List<Sample> tmp = histologyQuery.list(dc); |
1826 |
07 Feb 13 |
nicklas |
160 |
List<Histology> histology = new ArrayList<Histology>(tmp.size()); |
1826 |
07 Feb 13 |
nicklas |
161 |
for (Sample s : tmp) |
1826 |
07 Feb 13 |
nicklas |
162 |
{ |
1826 |
07 Feb 13 |
nicklas |
163 |
histology.add(new Histology(s)); |
1826 |
07 Feb 13 |
nicklas |
164 |
} |
1826 |
07 Feb 13 |
nicklas |
165 |
return histology; |
1826 |
07 Feb 13 |
nicklas |
166 |
} |
1826 |
07 Feb 13 |
nicklas |
167 |
|
1826 |
07 Feb 13 |
nicklas |
168 |
|
1826 |
07 Feb 13 |
nicklas |
169 |
/** |
1681 |
01 Jun 12 |
nicklas |
Get a Histology when the id is known. |
1669 |
29 May 12 |
nicklas |
171 |
*/ |
1669 |
29 May 12 |
nicklas |
172 |
public static Histology getById(DbControl dc, int id) |
1669 |
29 May 12 |
nicklas |
173 |
{ |
1669 |
29 May 12 |
nicklas |
174 |
return new Histology(Sample.getById(dc, id)); |
1669 |
29 May 12 |
nicklas |
175 |
} |
1669 |
29 May 12 |
nicklas |
176 |
|
1669 |
29 May 12 |
nicklas |
177 |
|
1669 |
29 May 12 |
nicklas |
178 |
private JSONObject jsonWell; |
1669 |
29 May 12 |
nicklas |
179 |
|
1669 |
29 May 12 |
nicklas |
180 |
private Histology(Sample sample) |
1669 |
29 May 12 |
nicklas |
181 |
{ |
1669 |
29 May 12 |
nicklas |
182 |
super(sample); |
1669 |
29 May 12 |
nicklas |
183 |
|
1669 |
29 May 12 |
nicklas |
184 |
} |
1669 |
29 May 12 |
nicklas |
185 |
|
1669 |
29 May 12 |
nicklas |
186 |
|
1669 |
29 May 12 |
nicklas |
187 |
/** |
1669 |
29 May 12 |
nicklas |
Get the real sample that represents this Histology item in BASE. |
1669 |
29 May 12 |
nicklas |
189 |
*/ |
1669 |
29 May 12 |
nicklas |
190 |
public Sample getSample() |
1669 |
29 May 12 |
nicklas |
191 |
{ |
1669 |
29 May 12 |
nicklas |
192 |
return getItem(); |
1669 |
29 May 12 |
nicklas |
193 |
} |
1669 |
29 May 12 |
nicklas |
194 |
|
1669 |
29 May 12 |
nicklas |
195 |
@Override |
1669 |
29 May 12 |
nicklas |
196 |
protected void initJSON(JSONObject json) |
1669 |
29 May 12 |
nicklas |
197 |
{ |
1669 |
29 May 12 |
nicklas |
198 |
super.initJSON(json); |
1669 |
29 May 12 |
nicklas |
199 |
if (jsonWell != null) json.put("bioWell", jsonWell); |
1669 |
29 May 12 |
nicklas |
200 |
|
1669 |
29 May 12 |
nicklas |
201 |
} |
1669 |
29 May 12 |
nicklas |
202 |
|
1669 |
29 May 12 |
nicklas |
203 |
/** |
1669 |
29 May 12 |
nicklas |
Load information about the plate and location the current RNA |
1669 |
29 May 12 |
nicklas |
is located on. |
1669 |
29 May 12 |
nicklas |
206 |
*/ |
1669 |
29 May 12 |
nicklas |
207 |
public JSONObject loadBioPlateLocation() |
1669 |
29 May 12 |
nicklas |
208 |
{ |
1826 |
07 Feb 13 |
nicklas |
209 |
if (jsonWell == null) |
1669 |
29 May 12 |
nicklas |
210 |
{ |
2134 |
11 Nov 13 |
nicklas |
211 |
jsonWell = JsonUtil.getBioWellAsJSON(getItem().getBioWell(), true); |
1669 |
29 May 12 |
nicklas |
212 |
} |
1669 |
29 May 12 |
nicklas |
213 |
return jsonWell; |
1669 |
29 May 12 |
nicklas |
214 |
} |
1826 |
07 Feb 13 |
nicklas |
215 |
|
1669 |
29 May 12 |
nicklas |
216 |
|
1669 |
29 May 12 |
nicklas |
217 |
} |