1282 |
25 Jan 11 |
nicklas |
1 |
package net.sf.basedb.reggie; |
1282 |
25 Jan 11 |
nicklas |
2 |
|
5885 |
30 Mar 20 |
nicklas |
3 |
import java.io.ByteArrayOutputStream; |
3506 |
23 Sep 15 |
nicklas |
4 |
import java.io.FileNotFoundException; |
3506 |
23 Sep 15 |
nicklas |
5 |
import java.io.IOException; |
2859 |
27 Oct 14 |
nicklas |
6 |
import java.io.InputStream; |
2859 |
27 Oct 14 |
nicklas |
7 |
import java.net.URL; |
2685 |
19 Sep 14 |
nicklas |
8 |
import java.util.ArrayList; |
6410 |
20 Sep 21 |
nicklas |
9 |
import java.util.Collection; |
1326 |
29 Mar 11 |
nicklas |
10 |
import java.util.Collections; |
4306 |
17 Jan 17 |
nicklas |
11 |
import java.util.HashMap; |
1283 |
01 Feb 11 |
nicklas |
12 |
import java.util.List; |
4306 |
17 Jan 17 |
nicklas |
13 |
import java.util.Map; |
1560 |
14 Mar 12 |
nicklas |
14 |
import java.util.Set; |
1827 |
07 Feb 13 |
nicklas |
15 |
import java.util.regex.Pattern; |
1283 |
01 Feb 11 |
nicklas |
16 |
|
3973 |
26 May 16 |
nicklas |
17 |
import javax.servlet.ServletRequest; |
3973 |
26 May 16 |
nicklas |
18 |
|
7024 |
07 Feb 23 |
nicklas |
19 |
import org.apache.commons.lang3.time.FastDateFormat; |
3009 |
04 Dec 14 |
nicklas |
20 |
import org.jdom2.Document; |
4306 |
17 Jan 17 |
nicklas |
21 |
import org.jdom2.Element; |
2859 |
27 Oct 14 |
nicklas |
22 |
import org.slf4j.LoggerFactory; |
2859 |
27 Oct 14 |
nicklas |
23 |
|
4313 |
20 Jan 17 |
nicklas |
24 |
import net.sf.basedb.clients.web.extensions.service.Services; |
1463 |
14 Nov 11 |
martin |
25 |
import net.sf.basedb.core.AnnotationTypeCategory; |
2685 |
19 Sep 14 |
nicklas |
26 |
import net.sf.basedb.core.AnyToAny; |
3973 |
26 May 16 |
nicklas |
27 |
import net.sf.basedb.core.Application; |
2685 |
19 Sep 14 |
nicklas |
28 |
import net.sf.basedb.core.BasicItem; |
2859 |
27 Oct 14 |
nicklas |
29 |
import net.sf.basedb.core.ConfigurationException; |
1283 |
01 Feb 11 |
nicklas |
30 |
import net.sf.basedb.core.DbControl; |
4680 |
21 Feb 18 |
nicklas |
31 |
import net.sf.basedb.core.Directory; |
2685 |
19 Sep 14 |
nicklas |
32 |
import net.sf.basedb.core.File; |
2685 |
19 Sep 14 |
nicklas |
33 |
import net.sf.basedb.core.FileSetMember; |
2685 |
19 Sep 14 |
nicklas |
34 |
import net.sf.basedb.core.FileStoreEnabled; |
1283 |
01 Feb 11 |
nicklas |
35 |
import net.sf.basedb.core.Include; |
2685 |
19 Sep 14 |
nicklas |
36 |
import net.sf.basedb.core.Item; |
1283 |
01 Feb 11 |
nicklas |
37 |
import net.sf.basedb.core.ItemQuery; |
3033 |
12 Dec 14 |
nicklas |
38 |
import net.sf.basedb.core.Project; |
3033 |
12 Dec 14 |
nicklas |
39 |
import net.sf.basedb.core.SessionControl; |
3033 |
12 Dec 14 |
nicklas |
40 |
import net.sf.basedb.core.SystemItems; |
1283 |
01 Feb 11 |
nicklas |
41 |
import net.sf.basedb.core.Type; |
3033 |
12 Dec 14 |
nicklas |
42 |
import net.sf.basedb.core.User; |
1283 |
01 Feb 11 |
nicklas |
43 |
import net.sf.basedb.core.query.Expressions; |
1283 |
01 Feb 11 |
nicklas |
44 |
import net.sf.basedb.core.query.Hql; |
1283 |
01 Feb 11 |
nicklas |
45 |
import net.sf.basedb.core.query.Restrictions; |
4306 |
17 Jan 17 |
nicklas |
46 |
import net.sf.basedb.opengrid.service.OpenGridService; |
5376 |
23 Apr 19 |
nicklas |
47 |
import net.sf.basedb.reggie.activity.ActivityLog; |
1524 |
25 Jan 12 |
nicklas |
48 |
import net.sf.basedb.reggie.converter.DateToStringConverter; |
1524 |
25 Jan 12 |
nicklas |
49 |
import net.sf.basedb.reggie.converter.StringToDateConverter; |
5554 |
13 Aug 19 |
nicklas |
50 |
import net.sf.basedb.reggie.counter.CounterService; |
3988 |
10 Jun 16 |
nicklas |
51 |
import net.sf.basedb.reggie.dao.ClientApp; |
2892 |
04 Nov 14 |
nicklas |
52 |
import net.sf.basedb.util.FileUtil; |
3907 |
29 Apr 16 |
nicklas |
53 |
import net.sf.basedb.util.Values; |
3009 |
04 Dec 14 |
nicklas |
54 |
import net.sf.basedb.util.XmlUtil2; |
4313 |
20 Jan 17 |
nicklas |
55 |
import net.sf.basedb.util.extensions.Extension; |
4313 |
20 Jan 17 |
nicklas |
56 |
import net.sf.basedb.util.extensions.ExtensionPoint; |
4313 |
20 Jan 17 |
nicklas |
57 |
import net.sf.basedb.util.extensions.Registry; |
4313 |
20 Jan 17 |
nicklas |
58 |
import net.sf.basedb.util.extensions.events.EventFilter; |
4313 |
20 Jan 17 |
nicklas |
59 |
import net.sf.basedb.util.extensions.events.EventHandler; |
4313 |
20 Jan 17 |
nicklas |
60 |
import net.sf.basedb.util.extensions.events.EventType; |
4313 |
20 Jan 17 |
nicklas |
61 |
import net.sf.basedb.util.extensions.events.ExtensionEventFilter; |
7080 |
27 Mar 23 |
nicklas |
62 |
import net.sf.basedb.util.extensions.logging.ExtensionsLog; |
7080 |
27 Mar 23 |
nicklas |
63 |
import net.sf.basedb.util.extensions.logging.ExtensionsLogger; |
1283 |
01 Feb 11 |
nicklas |
64 |
|
1282 |
25 Jan 11 |
nicklas |
65 |
/** |
1282 |
25 Jan 11 |
nicklas |
Global constants for the Reggie package. |
1282 |
25 Jan 11 |
nicklas |
@since 1.0 |
1282 |
25 Jan 11 |
nicklas |
68 |
*/ |
1282 |
25 Jan 11 |
nicklas |
69 |
public class Reggie |
1282 |
25 Jan 11 |
nicklas |
70 |
{ |
7080 |
27 Mar 23 |
nicklas |
71 |
private static final ExtensionsLogger logger = |
7080 |
27 Mar 23 |
nicklas |
72 |
ExtensionsLog.getLogger("net.sf.basedb.reggie", true).wrap(LoggerFactory.getLogger(Reggie.class)); |
2859 |
27 Oct 14 |
nicklas |
73 |
|
3973 |
26 May 16 |
nicklas |
74 |
/** |
6837 |
05 Sep 22 |
nicklas |
The current version of this package. Calling toString() to ensure that |
6837 |
05 Sep 22 |
nicklas |
the value is not inlined to other places. |
1302 |
28 Feb 11 |
nicklas |
77 |
*/ |
7446 |
20 Nov 23 |
nicklas |
78 |
public static final String VERSION = "4.51-dev".toString(); |
1283 |
01 Feb 11 |
nicklas |
79 |
|
1284 |
08 Feb 11 |
nicklas |
80 |
/** |
1524 |
25 Jan 12 |
nicklas |
Default converter for date values to string values: yyyyMMdd |
1524 |
25 Jan 12 |
nicklas |
@since 2.2 |
1524 |
25 Jan 12 |
nicklas |
83 |
*/ |
7024 |
07 Feb 23 |
nicklas |
84 |
public static final DateToStringConverter CONVERTER_DATE_TO_STRING = new DateToStringConverter(FastDateFormat.getInstance("yyyyMMdd")); |
1524 |
25 Jan 12 |
nicklas |
85 |
|
1524 |
25 Jan 12 |
nicklas |
86 |
/** |
3824 |
04 Apr 16 |
nicklas |
Alternate converter for date values with a '-' separator: yyyy-MM-dd |
3824 |
04 Apr 16 |
nicklas |
@since 4.3 |
3824 |
04 Apr 16 |
nicklas |
89 |
*/ |
7024 |
07 Feb 23 |
nicklas |
90 |
public static final DateToStringConverter CONVERTER_DATE_TO_STRING_WITH_SEPARATOR = new DateToStringConverter(FastDateFormat.getInstance("yyyy-MM-dd")); |
3824 |
04 Apr 16 |
nicklas |
91 |
|
3824 |
04 Apr 16 |
nicklas |
92 |
/** |
1524 |
25 Jan 12 |
nicklas |
Default converter for string values to date values: yyyyMMdd |
1524 |
25 Jan 12 |
nicklas |
@since 2.2 |
1524 |
25 Jan 12 |
nicklas |
95 |
*/ |
7024 |
07 Feb 23 |
nicklas |
96 |
public static final StringToDateConverter CONVERTER_STRING_TO_DATE = new StringToDateConverter(FastDateFormat.getInstance("yyyyMMdd")); |
1524 |
25 Jan 12 |
nicklas |
97 |
|
1524 |
25 Jan 12 |
nicklas |
98 |
/** |
5262 |
24 Jan 19 |
nicklas |
Alternate converter for date values with a '-' separator: yyyy-MM-dd |
5262 |
24 Jan 19 |
nicklas |
@since 4.21 |
5262 |
24 Jan 19 |
nicklas |
101 |
*/ |
7024 |
07 Feb 23 |
nicklas |
102 |
public static final StringToDateConverter CONVERTER_STRING_WITH_SEPARATOR_TO_DATE = new StringToDateConverter(FastDateFormat.getInstance("yyyy-MM-dd")); |
5262 |
24 Jan 19 |
nicklas |
103 |
|
5262 |
24 Jan 19 |
nicklas |
104 |
|
5262 |
24 Jan 19 |
nicklas |
105 |
/** |
1524 |
25 Jan 12 |
nicklas |
Default converter for date+time values to string values: yyyyMMdd HHmm |
1524 |
25 Jan 12 |
nicklas |
@since 2.2 |
1524 |
25 Jan 12 |
nicklas |
108 |
*/ |
7024 |
07 Feb 23 |
nicklas |
109 |
public static final DateToStringConverter CONVERTER_DATETIME_TO_STRING = new DateToStringConverter(FastDateFormat.getInstance("yyyyMMdd HHmm")); |
3939 |
16 May 16 |
nicklas |
110 |
|
3939 |
16 May 16 |
nicklas |
111 |
/** |
4404 |
17 Mar 17 |
nicklas |
Default converter for date+time (with seconds) values to string values: yyyyMMdd HHmmss |
4404 |
17 Mar 17 |
nicklas |
@since 4.10 |
4404 |
17 Mar 17 |
nicklas |
114 |
*/ |
7024 |
07 Feb 23 |
nicklas |
115 |
public static final DateToStringConverter CONVERTER_TIMESTAMP_TO_STRING = new DateToStringConverter(FastDateFormat.getInstance("yyyyMMdd HHmmss")); |
4404 |
17 Mar 17 |
nicklas |
116 |
|
4404 |
17 Mar 17 |
nicklas |
117 |
/** |
3939 |
16 May 16 |
nicklas |
Alternate converter for date+time values with separators: yyyy-MM-dd HH:mm |
3939 |
16 May 16 |
nicklas |
@since 4.5 |
3939 |
16 May 16 |
nicklas |
120 |
*/ |
7024 |
07 Feb 23 |
nicklas |
121 |
public static final DateToStringConverter CONVERTER_DATETIME_TO_STRING_WITH_SEPARATOR = new DateToStringConverter(FastDateFormat.getInstance("yyyy-MM-dd HH:mm")); |
1524 |
25 Jan 12 |
nicklas |
122 |
|
1524 |
25 Jan 12 |
nicklas |
123 |
/** |
5423 |
13 May 19 |
nicklas |
Alternate converter for time values with separators: HH:mm |
5423 |
13 May 19 |
nicklas |
@since 4.23 |
5423 |
13 May 19 |
nicklas |
126 |
*/ |
7024 |
07 Feb 23 |
nicklas |
127 |
public static final DateToStringConverter CONVERTER_TIME_TO_STRING_WITH_SEPARATOR = new DateToStringConverter(FastDateFormat.getInstance("HH:mm")); |
5423 |
13 May 19 |
nicklas |
128 |
|
5423 |
13 May 19 |
nicklas |
129 |
/** |
1524 |
25 Jan 12 |
nicklas |
Default converter for string values to date+time values: yyyyMMdd HHmm |
1524 |
25 Jan 12 |
nicklas |
@since 2.2 |
1524 |
25 Jan 12 |
nicklas |
132 |
*/ |
7024 |
07 Feb 23 |
nicklas |
133 |
public static final StringToDateConverter CONVERTER_STRING_TO_DATETIME = new StringToDateConverter(FastDateFormat.getInstance("yyyyMMdd HHmm")); |
1524 |
25 Jan 12 |
nicklas |
134 |
|
1560 |
14 Mar 12 |
nicklas |
135 |
/** |
1560 |
14 Mar 12 |
nicklas |
Include options to make a query only return items in the currently active project. |
1560 |
14 Mar 12 |
nicklas |
Use with {@link ItemQuery#setIncludes(java.util.Collection)} |
1560 |
14 Mar 12 |
nicklas |
@since 2.4 |
1560 |
14 Mar 12 |
nicklas |
139 |
*/ |
1560 |
14 Mar 12 |
nicklas |
140 |
public static final Set<Include> INCLUDE_IN_CURRENT_PROJECT = Collections.singleton(Include.IN_PROJECT); |
4000 |
17 Jun 16 |
nicklas |
141 |
|
4000 |
17 Jun 16 |
nicklas |
142 |
/** |
4000 |
17 Jun 16 |
nicklas |
Include options to make a query only return items shared to the currently |
4000 |
17 Jun 16 |
nicklas |
logged in user. |
4000 |
17 Jun 16 |
nicklas |
Use with {@link ItemQuery#setIncludes(java.util.Collection)} |
4000 |
17 Jun 16 |
nicklas |
@since 4.6 |
4000 |
17 Jun 16 |
nicklas |
147 |
*/ |
4001 |
17 Jun 16 |
nicklas |
148 |
public static final Set<Include> INCLUDE_SHARED_TO_ME = Collections.singleton(Include.SHARED); |
4001 |
17 Jun 16 |
nicklas |
//public static final Set<Include> INCLUDE_SHARED_TO_ME = new HashSet<>(Include.ALL); |
1524 |
25 Jan 12 |
nicklas |
150 |
|
1827 |
07 Feb 13 |
nicklas |
151 |
/** |
1827 |
07 Feb 13 |
nicklas |
Regular expression pattern that can be match against a string to see |
1827 |
07 Feb 13 |
nicklas |
if it contains a case name, eg. it starts with 7 digits, optionally |
6964 |
19 Dec 22 |
nicklas |
followed by a dot and suffixes |
1827 |
07 Feb 13 |
nicklas |
@since 2.11 |
1827 |
07 Feb 13 |
nicklas |
156 |
*/ |
6964 |
19 Dec 22 |
nicklas |
157 |
public static final Pattern CASE_NAME_PATTERN = Pattern.compile("\\d{7}(\\.[a-z0-9]+)*"); |
1463 |
14 Nov 11 |
martin |
158 |
|
1463 |
14 Nov 11 |
martin |
159 |
/** |
2578 |
15 Aug 14 |
nicklas |
Path to the directory on the BASE file system where secondary analysis files |
2578 |
15 Aug 14 |
nicklas |
are saved. This directory maps some files to the "project-archive" directory |
2578 |
15 Aug 14 |
nicklas |
on the file server. |
2578 |
15 Aug 14 |
nicklas |
@since 2.16 |
2578 |
15 Aug 14 |
nicklas |
164 |
*/ |
2578 |
15 Aug 14 |
nicklas |
165 |
public static final String SECONDARY_ANALYSIS_DIR = "/home/SCANB/SecondaryAnalysis"; |
2578 |
15 Aug 14 |
nicklas |
166 |
|
3600 |
13 Nov 15 |
nicklas |
167 |
/** |
3600 |
13 Nov 15 |
nicklas |
Path to the directory on the BASE file system where secondary analysis files |
3600 |
13 Nov 15 |
nicklas |
from external samples are saved. This directory maps some files to the |
3600 |
13 Nov 15 |
nicklas |
"external-archive" directory on the file server. |
3600 |
13 Nov 15 |
nicklas |
@since 4.0 |
3600 |
13 Nov 15 |
nicklas |
172 |
*/ |
3600 |
13 Nov 15 |
nicklas |
173 |
public static final String EXTERNAL_ANALYSIS_DIR = "/home/External/SecondaryAnalysis"; |
2859 |
27 Oct 14 |
nicklas |
174 |
|
2578 |
15 Aug 14 |
nicklas |
175 |
/** |
4028 |
26 Jul 16 |
nicklas |
Path to the directory on the BASE file system where reports delivered to external |
4028 |
26 Jul 16 |
nicklas |
sites are stored. |
4028 |
26 Jul 16 |
nicklas |
@since 4.6 |
4028 |
26 Jul 16 |
nicklas |
179 |
*/ |
4028 |
26 Jul 16 |
nicklas |
180 |
public static final String DELIVERY_DIR = "/home/Delivery"; |
4028 |
26 Jul 16 |
nicklas |
181 |
|
4028 |
26 Jul 16 |
nicklas |
182 |
/** |
4512 |
31 May 17 |
nicklas |
Path to the directory on the BASE file system where frozen tissue CSV files are expected |
4512 |
31 May 17 |
nicklas |
to be stored. |
4512 |
31 May 17 |
nicklas |
@since 4.10 |
4512 |
31 May 17 |
nicklas |
186 |
*/ |
4512 |
31 May 17 |
nicklas |
187 |
public static final String FROZEN_TISSUE_FILES = "/home/SCANB/FrozenTissueFiles"; |
4512 |
31 May 17 |
nicklas |
188 |
|
5397 |
03 May 19 |
nicklas |
189 |
/** |
5397 |
03 May 19 |
nicklas |
Path to the directory on the BASE file system where import |
5397 |
03 May 19 |
nicklas |
files for MIPs aliquot plates are expected. |
5397 |
03 May 19 |
nicklas |
@since 4.23 |
5397 |
03 May 19 |
nicklas |
193 |
*/ |
5397 |
03 May 19 |
nicklas |
194 |
public static final String MIPS_IMPORT_FILES = "/home/SCANB/MIPsImportFiles"; |
5397 |
03 May 19 |
nicklas |
195 |
|
5889 |
06 Apr 20 |
nicklas |
196 |
/** |
7139 |
27 Apr 23 |
nicklas |
Path to the directory on the BASE file system where import |
7139 |
27 Apr 23 |
nicklas |
files for transport boxes are expected. |
7139 |
27 Apr 23 |
nicklas |
@since 4.47 |
7139 |
27 Apr 23 |
nicklas |
200 |
*/ |
7139 |
27 Apr 23 |
nicklas |
201 |
public static final String TRANSPORT_BOX_IMPORT_FILES = "/home/SCANB/BiomaterialPathology"; |
7139 |
27 Apr 23 |
nicklas |
202 |
|
7139 |
27 Apr 23 |
nicklas |
203 |
|
7139 |
27 Apr 23 |
nicklas |
204 |
/** |
5889 |
06 Apr 20 |
nicklas |
Path to the directory on the BASE file system where additional template files are |
5889 |
06 Apr 20 |
nicklas |
stored. |
5889 |
06 Apr 20 |
nicklas |
@since 4.26 |
5889 |
06 Apr 20 |
nicklas |
208 |
*/ |
5889 |
06 Apr 20 |
nicklas |
209 |
public static final String TEMPLATES_DIR = "/home/SCANB/Templates"; |
5889 |
06 Apr 20 |
nicklas |
210 |
|
4512 |
31 May 17 |
nicklas |
211 |
/** |
6277 |
03 Jun 21 |
nicklas |
Path to the directory on the BASE file system where referral ID log files are stored. |
6277 |
03 Jun 21 |
nicklas |
@since 4.31.2 |
6277 |
03 Jun 21 |
nicklas |
214 |
*/ |
6277 |
03 Jun 21 |
nicklas |
215 |
public static final String REFERRAL_LOGS_DIR = "/home/SCANB/ReferralIdLogs"; |
6277 |
03 Jun 21 |
nicklas |
216 |
|
6277 |
03 Jun 21 |
nicklas |
217 |
|
6277 |
03 Jun 21 |
nicklas |
218 |
/** |
5892 |
07 Apr 20 |
nicklas |
Path to the directory on the BASE file system where files associated with |
5892 |
07 Apr 20 |
nicklas |
external library plates are stored. |
5892 |
07 Apr 20 |
nicklas |
@since 4.26 |
5892 |
07 Apr 20 |
nicklas |
222 |
*/ |
5892 |
07 Apr 20 |
nicklas |
223 |
public static final String EXTERNAL_LIB_PLATES_DIR = "/home/SCANB/ExternalLibPlateFiles"; |
5892 |
07 Apr 20 |
nicklas |
224 |
|
5892 |
07 Apr 20 |
nicklas |
225 |
/** |
6960 |
13 Dec 22 |
nicklas |
Path to the directory on the BASE file system where JSON files with metadata |
6960 |
13 Dec 22 |
nicklas |
about externally processed samples are saved. |
6960 |
13 Dec 22 |
nicklas |
@since 4.41.3 |
6960 |
13 Dec 22 |
nicklas |
229 |
*/ |
6960 |
13 Dec 22 |
nicklas |
230 |
public static final String EXTERNAL_JSON_IMPORT_DIR = "/home/SCANB/ExternalImportJSON"; |
6960 |
13 Dec 22 |
nicklas |
231 |
|
6960 |
13 Dec 22 |
nicklas |
232 |
/** |
4138 |
29 Sep 16 |
nicklas |
This ID is used on Sample outtake lists. |
4138 |
29 Sep 16 |
nicklas |
@since 4.8 |
4138 |
29 Sep 16 |
nicklas |
235 |
*/ |
4138 |
29 Sep 16 |
nicklas |
236 |
public static final String OUTTAKE_ALIQUOTS_LIST_ID = "net.sf.basedb.reggie.outtake.aliquots"; |
4138 |
29 Sep 16 |
nicklas |
237 |
|
4138 |
29 Sep 16 |
nicklas |
238 |
|
4138 |
29 Sep 16 |
nicklas |
239 |
/** |
1284 |
08 Feb 11 |
nicklas |
List all annotation types with the given name. |
1463 |
14 Nov 11 |
martin |
@since 2.0 |
1284 |
08 Feb 11 |
nicklas |
242 |
*/ |
1463 |
14 Nov 11 |
martin |
243 |
public static List<AnnotationTypeCategory> listAnnotationTypeCategories(DbControl dc, String name) |
1463 |
14 Nov 11 |
martin |
244 |
{ |
1463 |
14 Nov 11 |
martin |
245 |
ItemQuery<AnnotationTypeCategory> query = AnnotationTypeCategory.getQuery(); |
1463 |
14 Nov 11 |
martin |
246 |
query.restrict(Restrictions.eq(Hql.property("name"), Expressions.parameter("name", name, Type.STRING))); |
1463 |
14 Nov 11 |
martin |
247 |
query.include(Include.ALL); |
1463 |
14 Nov 11 |
martin |
248 |
return query.list(dc); |
1463 |
14 Nov 11 |
martin |
249 |
} |
1463 |
14 Nov 11 |
martin |
250 |
|
1672 |
30 May 12 |
nicklas |
251 |
/** |
1672 |
30 May 12 |
nicklas |
Compare two comparable objects with null safety. Two null objects |
1672 |
30 May 12 |
nicklas |
are considered equal and all null objects are sorted after all non-null |
1672 |
30 May 12 |
nicklas |
objects. |
1672 |
30 May 12 |
nicklas |
@return A negative value if the first argument should be sorted before the second, |
1672 |
30 May 12 |
nicklas |
zero if they are equal, a positive value if the second argument should be sorted |
1672 |
30 May 12 |
nicklas |
before the first |
1672 |
30 May 12 |
nicklas |
258 |
*/ |
1672 |
30 May 12 |
nicklas |
259 |
public static <T extends Comparable<T>> int nullSafeCompare(T o1, T o2) |
1672 |
30 May 12 |
nicklas |
260 |
{ |
1672 |
30 May 12 |
nicklas |
261 |
int result = 0; |
1672 |
30 May 12 |
nicklas |
262 |
if (o1 == o2) |
1672 |
30 May 12 |
nicklas |
263 |
{} |
1672 |
30 May 12 |
nicklas |
264 |
else if (o1 == null) |
1672 |
30 May 12 |
nicklas |
265 |
{ |
1672 |
30 May 12 |
nicklas |
266 |
result = 1; |
1672 |
30 May 12 |
nicklas |
267 |
} |
1672 |
30 May 12 |
nicklas |
268 |
else if (o2 == null) |
1672 |
30 May 12 |
nicklas |
269 |
{ |
1672 |
30 May 12 |
nicklas |
270 |
result = -1; |
1672 |
30 May 12 |
nicklas |
271 |
} |
1672 |
30 May 12 |
nicklas |
272 |
else |
1672 |
30 May 12 |
nicklas |
273 |
{ |
1672 |
30 May 12 |
nicklas |
274 |
result = o1.compareTo(o2); |
1672 |
30 May 12 |
nicklas |
275 |
} |
1672 |
30 May 12 |
nicklas |
276 |
return result; |
1672 |
30 May 12 |
nicklas |
277 |
} |
1672 |
30 May 12 |
nicklas |
278 |
|
1975 |
15 May 13 |
nicklas |
279 |
/** |
3309 |
06 May 15 |
nicklas |
Return the first non-null value. If all |
3309 |
06 May 15 |
nicklas |
values are null, null is returned. |
3309 |
06 May 15 |
nicklas |
@since 3.4 |
3309 |
06 May 15 |
nicklas |
283 |
*/ |
3309 |
06 May 15 |
nicklas |
284 |
@SuppressWarnings("unchecked") |
3309 |
06 May 15 |
nicklas |
285 |
public static <T> T firstNonNull(T... values) |
3309 |
06 May 15 |
nicklas |
286 |
{ |
3309 |
06 May 15 |
nicklas |
287 |
if (values != null) |
3309 |
06 May 15 |
nicklas |
288 |
{ |
3309 |
06 May 15 |
nicklas |
289 |
for (T t : values) |
3309 |
06 May 15 |
nicklas |
290 |
{ |
3309 |
06 May 15 |
nicklas |
291 |
if (t != null) return t; |
3309 |
06 May 15 |
nicklas |
292 |
} |
3309 |
06 May 15 |
nicklas |
293 |
} |
3309 |
06 May 15 |
nicklas |
294 |
return null; |
3309 |
06 May 15 |
nicklas |
295 |
} |
3309 |
06 May 15 |
nicklas |
296 |
|
3309 |
06 May 15 |
nicklas |
297 |
/** |
6388 |
15 Sep 21 |
nicklas |
Join texts parts and make sure a period is ending each sentence. |
6389 |
15 Sep 21 |
nicklas |
@since 4.32 |
6388 |
15 Sep 21 |
nicklas |
300 |
*/ |
6410 |
20 Sep 21 |
nicklas |
301 |
public static String joinTexts(Collection<String> texts) |
6388 |
15 Sep 21 |
nicklas |
302 |
{ |
6388 |
15 Sep 21 |
nicklas |
303 |
StringBuilder sb = new StringBuilder(); |
6388 |
15 Sep 21 |
nicklas |
304 |
for (String t: texts) |
6388 |
15 Sep 21 |
nicklas |
305 |
{ |
6388 |
15 Sep 21 |
nicklas |
306 |
if (t == null || t.equals("")) continue; |
6388 |
15 Sep 21 |
nicklas |
307 |
if (sb.length() > 0) |
6388 |
15 Sep 21 |
nicklas |
308 |
{ |
6388 |
15 Sep 21 |
nicklas |
309 |
sb.append(sb.charAt(sb.length()-1) != '.' ? ". " : " "); |
6388 |
15 Sep 21 |
nicklas |
310 |
} |
6388 |
15 Sep 21 |
nicklas |
311 |
sb.append(t); |
6388 |
15 Sep 21 |
nicklas |
312 |
} |
6410 |
20 Sep 21 |
nicklas |
313 |
if (sb.length() > 0 && sb.charAt(sb.length()-1) != '.') |
6410 |
20 Sep 21 |
nicklas |
314 |
{ |
6410 |
20 Sep 21 |
nicklas |
315 |
sb.append("."); |
6410 |
20 Sep 21 |
nicklas |
316 |
} |
6388 |
15 Sep 21 |
nicklas |
317 |
return sb.toString(); |
6388 |
15 Sep 21 |
nicklas |
318 |
} |
6388 |
15 Sep 21 |
nicklas |
319 |
|
6388 |
15 Sep 21 |
nicklas |
320 |
/** |
1975 |
15 May 13 |
nicklas |
Round a floating point value to a given number of decimals. |
1975 |
15 May 13 |
nicklas |
@since 2.12 |
1975 |
15 May 13 |
nicklas |
323 |
*/ |
1975 |
15 May 13 |
nicklas |
324 |
public static float round(float value, int decimals) |
1975 |
15 May 13 |
nicklas |
325 |
{ |
1975 |
15 May 13 |
nicklas |
326 |
double factor = Math.pow(10, decimals); |
1975 |
15 May 13 |
nicklas |
327 |
return (float)(Math.round(factor * value) / factor); |
1975 |
15 May 13 |
nicklas |
328 |
} |
1975 |
15 May 13 |
nicklas |
329 |
|
2386 |
25 Apr 14 |
nicklas |
330 |
/** |
2386 |
25 Apr 14 |
nicklas |
Convert to lower case and remove all characters not in [a-z0-9_] |
2386 |
25 Apr 14 |
nicklas |
@since 2.16 |
2386 |
25 Apr 14 |
nicklas |
333 |
*/ |
2386 |
25 Apr 14 |
nicklas |
334 |
public static String makeSafeProjectName(String name) |
2386 |
25 Apr 14 |
nicklas |
335 |
{ |
2386 |
25 Apr 14 |
nicklas |
336 |
return name.toLowerCase().replaceAll("[^a-z0-9_]", ""); |
2386 |
25 Apr 14 |
nicklas |
337 |
} |
3907 |
29 Apr 16 |
nicklas |
338 |
|
4157 |
07 Oct 16 |
nicklas |
339 |
/** |
4157 |
07 Oct 16 |
nicklas |
Convert to lower case and replace all characters not in [a-z0-9_-] with |
4157 |
07 Oct 16 |
nicklas |
341 |
-. |
4157 |
07 Oct 16 |
nicklas |
@since 4.8 |
4157 |
07 Oct 16 |
nicklas |
343 |
*/ |
4157 |
07 Oct 16 |
nicklas |
344 |
public static String makeSafeFileName(String name) |
4157 |
07 Oct 16 |
nicklas |
345 |
{ |
4157 |
07 Oct 16 |
nicklas |
346 |
return name.toLowerCase().replaceAll("[^a-z0-9_\\-]+", "-"); |
4157 |
07 Oct 16 |
nicklas |
347 |
} |
4157 |
07 Oct 16 |
nicklas |
348 |
|
5843 |
25 Feb 20 |
nicklas |
349 |
public static String formatCount(Number count) |
3907 |
29 Apr 16 |
nicklas |
350 |
{ |
7390 |
02 Nov 23 |
nicklas |
351 |
return formatCount(count, 1); |
7390 |
02 Nov 23 |
nicklas |
352 |
} |
7390 |
02 Nov 23 |
nicklas |
353 |
|
7390 |
02 Nov 23 |
nicklas |
354 |
public static String formatCount(Number count, int baseDecimals) |
7390 |
02 Nov 23 |
nicklas |
355 |
{ |
5843 |
25 Feb 20 |
nicklas |
356 |
if (count == null) return ""; |
5843 |
25 Feb 20 |
nicklas |
357 |
long c = count.longValue(); |
7114 |
14 Apr 23 |
nicklas |
358 |
if (c > 1_000_000_000) |
3907 |
29 Apr 16 |
nicklas |
359 |
{ |
7390 |
02 Nov 23 |
nicklas |
360 |
int numDecimals = c < 100_000_000_000l ? baseDecimals : baseDecimals-1; |
7114 |
14 Apr 23 |
nicklas |
361 |
return Values.formatNumber(c / 1_000_000_000f, numDecimals, "G"); |
3907 |
29 Apr 16 |
nicklas |
362 |
} |
7114 |
14 Apr 23 |
nicklas |
363 |
else if (c > 1_000_000) |
7114 |
14 Apr 23 |
nicklas |
364 |
{ |
7390 |
02 Nov 23 |
nicklas |
365 |
int numDecimals = c < 100_000_000l ? baseDecimals : baseDecimals-1; |
7114 |
14 Apr 23 |
nicklas |
366 |
return Values.formatNumber(c / 1_000_000f, numDecimals, "M"); |
7114 |
14 Apr 23 |
nicklas |
367 |
} |
5843 |
25 Feb 20 |
nicklas |
368 |
else if (c > 1000) |
3907 |
29 Apr 16 |
nicklas |
369 |
{ |
7390 |
02 Nov 23 |
nicklas |
370 |
int numDecimals = c < 100_000 ? baseDecimals : baseDecimals-1; |
5843 |
25 Feb 20 |
nicklas |
371 |
return Values.formatNumber(c / 1000f, numDecimals, "k"); |
3907 |
29 Apr 16 |
nicklas |
372 |
} |
5843 |
25 Feb 20 |
nicklas |
373 |
return Long.toString(c); |
3907 |
29 Apr 16 |
nicklas |
374 |
} |
2386 |
25 Apr 14 |
nicklas |
375 |
|
2685 |
19 Sep 14 |
nicklas |
376 |
/** |
2801 |
13 Oct 14 |
nicklas |
Convert a data files folder to a BASE file system folder. |
2801 |
13 Oct 14 |
nicklas |
We want to use a prefix in the BASE file system to prevent |
2801 |
13 Oct 14 |
nicklas |
several thousands of subfolders inside a single folder. |
2801 |
13 Oct 14 |
nicklas |
The prefix should only be used if the data folder starts with |
2801 |
13 Oct 14 |
nicklas |
digits and is two levels deep. The first level is the first two |
2801 |
13 Oct 14 |
nicklas |
digits and the second level is the first four digits. |
2801 |
13 Oct 14 |
nicklas |
383 |
|
4551 |
03 Jul 17 |
nicklas |
Note that it must handle both the case when the dataFilesFolder |
4551 |
03 Jul 17 |
nicklas |
already have a site prefix and when it hasn't. |
4551 |
03 Jul 17 |
nicklas |
386 |
|
2801 |
13 Oct 14 |
nicklas |
Examples: |
2801 |
13 Oct 14 |
nicklas |
/1234567.1/l.r.m.c.lib.g --> /12/1234/1234567.1/l.r.m.c.lib.g |
4551 |
03 Jul 17 |
nicklas |
/12/1234567.1/l.r.m.c.lib.g --> /12/1234/1234567.1/l.r.m.c.lib.g |
2801 |
13 Oct 14 |
nicklas |
/debug/1234567.1/l.r.m.c.lib.g --> /debug/1234567.1/l.r.m.c.lib.g |
2801 |
13 Oct 14 |
nicklas |
/Stratagene/r.m.c.lib.g --> /Stratagene/r.m.c.lib.g |
2801 |
13 Oct 14 |
nicklas |
/SKBR3/m.c.lib.g --> /SKBR3/m.c.lib.g |
3600 |
13 Nov 15 |
nicklas |
/NN/K562/m.c.lib.g --> /NN/K562/m.c.lib.g |
2801 |
13 Oct 14 |
nicklas |
@since 2.16.1 |
2801 |
13 Oct 14 |
nicklas |
395 |
*/ |
2801 |
13 Oct 14 |
nicklas |
396 |
public static String convertDataFilesFolderToBaseFolder(String dataFilesFolder) |
2801 |
13 Oct 14 |
nicklas |
397 |
{ |
7124 |
21 Apr 23 |
nicklas |
// If the path starts with '/'+7 digits+'.'+at least one more digit or 'b' +'/' |
4551 |
03 Jul 17 |
nicklas |
// insert prefix based on first 2+4 digits |
4551 |
03 Jul 17 |
nicklas |
// (ignoring an already existing site prefix '/'+2 digits) |
7124 |
21 Apr 23 |
nicklas |
401 |
return dataFilesFolder.replaceFirst("^(/\\d\\d)?(((/\\d{2})\\d{2})\\d{3}\\.[b0-9]+/)", "$4$3$2"); |
2801 |
13 Oct 14 |
nicklas |
402 |
} |
2801 |
13 Oct 14 |
nicklas |
403 |
|
2801 |
13 Oct 14 |
nicklas |
404 |
/** |
5553 |
12 Aug 19 |
nicklas |
Check if an item with the given name is an external item. |
5553 |
12 Aug 19 |
nicklas |
@param name If the name starts with only digits the item |
5553 |
12 Aug 19 |
nicklas |
is not external and this method return false |
5553 |
12 Aug 19 |
nicklas |
@since 4.23 |
3600 |
13 Nov 15 |
nicklas |
409 |
*/ |
5553 |
12 Aug 19 |
nicklas |
410 |
public static boolean isExternalItem(String name) |
3600 |
13 Nov 15 |
nicklas |
411 |
{ |
4645 |
12 Dec 17 |
nicklas |
412 |
return !name.matches("\\d+\\..+"); |
3600 |
13 Nov 15 |
nicklas |
413 |
} |
3600 |
13 Nov 15 |
nicklas |
414 |
|
5524 |
24 Jun 19 |
nicklas |
415 |
/** |
5594 |
11 Sep 19 |
nicklas |
For an external item, get the group name that should have |
5594 |
11 Sep 19 |
nicklas |
read access to files that are created on the file server |
5594 |
11 Sep 19 |
nicklas |
(ExternalArchive). The returned group name should be used |
5594 |
11 Sep 19 |
nicklas |
with a 'chgrp <group> <file-or-folder>' command. |
5594 |
11 Sep 19 |
nicklas |
420 |
|
5594 |
11 Sep 19 |
nicklas |
Group names are linked to prefixes used on external items. |
5594 |
11 Sep 19 |
nicklas |
in reggie-config.xml: |
5594 |
11 Sep 19 |
nicklas |
423 |
|
5594 |
11 Sep 19 |
nicklas |
<external-samples> |
5594 |
11 Sep 19 |
nicklas |
<groupname prefix="..">...</groupname> |
5594 |
11 Sep 19 |
nicklas |
</external-samples> |
5594 |
11 Sep 19 |
nicklas |
427 |
|
5594 |
11 Sep 19 |
nicklas |
The prefix is extracted from the given name by taking all |
5594 |
11 Sep 19 |
nicklas |
characters before the first underscore (_). For example, |
5594 |
11 Sep 19 |
nicklas |
'NN_foobar.lib.g' --> 'NN'. |
5594 |
11 Sep 19 |
nicklas |
431 |
|
5594 |
11 Sep 19 |
nicklas |
@return A group name, or null if the name has no prefix or |
5594 |
11 Sep 19 |
nicklas |
if no group has been configured |
5594 |
11 Sep 19 |
nicklas |
@sice 4.23 |
5594 |
11 Sep 19 |
nicklas |
435 |
*/ |
5594 |
11 Sep 19 |
nicklas |
436 |
public static String getExternalGroup(String name) |
5594 |
11 Sep 19 |
nicklas |
437 |
{ |
5594 |
11 Sep 19 |
nicklas |
438 |
String groupName = null; |
5594 |
11 Sep 19 |
nicklas |
439 |
int i = name.indexOf('_'); |
5594 |
11 Sep 19 |
nicklas |
440 |
if (i > 0) |
5594 |
11 Sep 19 |
nicklas |
441 |
{ |
5594 |
11 Sep 19 |
nicklas |
442 |
String prefix = name.substring(0, i); |
5594 |
11 Sep 19 |
nicklas |
443 |
XmlConfig cfg = getConfig(); |
5594 |
11 Sep 19 |
nicklas |
444 |
groupName = cfg.getConfig("external-samples/groupname[@prefix='"+prefix+"']"); |
5594 |
11 Sep 19 |
nicklas |
445 |
} |
5594 |
11 Sep 19 |
nicklas |
446 |
return groupName; |
5594 |
11 Sep 19 |
nicklas |
447 |
} |
5594 |
11 Sep 19 |
nicklas |
448 |
|
5594 |
11 Sep 19 |
nicklas |
449 |
/** |
5524 |
24 Jun 19 |
nicklas |
Remove the prefix from the name. A prefix is a |
5524 |
24 Jun 19 |
nicklas |
number of letters/numbers followed by an underscore. |
5524 |
24 Jun 19 |
nicklas |
@since 4.23 |
5524 |
24 Jun 19 |
nicklas |
453 |
*/ |
5524 |
24 Jun 19 |
nicklas |
454 |
public static String removePrefix(String name) |
5524 |
24 Jun 19 |
nicklas |
455 |
{ |
5524 |
24 Jun 19 |
nicklas |
456 |
int i = name.indexOf('_'); |
5524 |
24 Jun 19 |
nicklas |
457 |
return i > 0 ? name.substring(i+1) : name; |
5524 |
24 Jun 19 |
nicklas |
458 |
} |
3600 |
13 Nov 15 |
nicklas |
459 |
|
3600 |
13 Nov 15 |
nicklas |
460 |
/** |
5930 |
06 May 20 |
nicklas |
Get the prefix from the name. A prefix is a |
5930 |
06 May 20 |
nicklas |
number of letters/numbers followed by an underscore. |
5930 |
06 May 20 |
nicklas |
Returns null if the name has no prefix. |
5930 |
06 May 20 |
nicklas |
@since 4.27 |
5930 |
06 May 20 |
nicklas |
465 |
*/ |
5930 |
06 May 20 |
nicklas |
466 |
public static String getPrefix(String name) |
5930 |
06 May 20 |
nicklas |
467 |
{ |
5930 |
06 May 20 |
nicklas |
468 |
int i = name.indexOf('_'); |
5930 |
06 May 20 |
nicklas |
469 |
return i > 0 ? name.substring(0, i) : null; |
5930 |
06 May 20 |
nicklas |
470 |
} |
5930 |
06 May 20 |
nicklas |
471 |
|
5930 |
06 May 20 |
nicklas |
472 |
/** |
2685 |
19 Sep 14 |
nicklas |
Mark all related files for removal. |
2685 |
19 Sep 14 |
nicklas |
@since 2.16 |
2685 |
19 Sep 14 |
nicklas |
475 |
*/ |
2685 |
19 Sep 14 |
nicklas |
476 |
public static List<File> removeAttachedFiles(DbControl dc, FileStoreEnabled item) |
2685 |
19 Sep 14 |
nicklas |
477 |
{ |
2685 |
19 Sep 14 |
nicklas |
478 |
List<File> files = new ArrayList<File>(); |
4680 |
21 Feb 18 |
nicklas |
479 |
|
2685 |
19 Sep 14 |
nicklas |
480 |
if (item.hasFileSet()) |
2685 |
19 Sep 14 |
nicklas |
481 |
{ |
2685 |
19 Sep 14 |
nicklas |
482 |
ItemQuery<FileSetMember> query = item.getFileSet().getMembers(); |
2685 |
19 Sep 14 |
nicklas |
483 |
for (FileSetMember fsm : query.list(dc)) |
2685 |
19 Sep 14 |
nicklas |
484 |
{ |
2685 |
19 Sep 14 |
nicklas |
485 |
File f = fsm.getFile(); |
4687 |
26 Feb 18 |
nicklas |
486 |
if (f.isWriteProtected()) |
4687 |
26 Feb 18 |
nicklas |
487 |
{ |
4687 |
26 Feb 18 |
nicklas |
488 |
f.setWriteProtected(false); |
4687 |
26 Feb 18 |
nicklas |
489 |
dc.reattachItem(f, true); // Needed since DELETE permissions is not granted otherwise |
4687 |
26 Feb 18 |
nicklas |
490 |
} |
2685 |
19 Sep 14 |
nicklas |
491 |
f.setRemoved(true); |
2685 |
19 Sep 14 |
nicklas |
492 |
files.add(f); |
2685 |
19 Sep 14 |
nicklas |
493 |
} |
2685 |
19 Sep 14 |
nicklas |
494 |
} |
2685 |
19 Sep 14 |
nicklas |
495 |
|
2685 |
19 Sep 14 |
nicklas |
496 |
ItemQuery<AnyToAny> query = AnyToAny.getLinksFrom((BasicItem)item); |
2685 |
19 Sep 14 |
nicklas |
497 |
for (AnyToAny ata : query.list(dc)) |
2685 |
19 Sep 14 |
nicklas |
498 |
{ |
2685 |
19 Sep 14 |
nicklas |
499 |
if (ata.getToType() == Item.FILE) |
2685 |
19 Sep 14 |
nicklas |
500 |
{ |
2685 |
19 Sep 14 |
nicklas |
501 |
File f = (File)ata.getTo(); |
4687 |
26 Feb 18 |
nicklas |
502 |
if (f.isWriteProtected()) |
4687 |
26 Feb 18 |
nicklas |
503 |
{ |
4687 |
26 Feb 18 |
nicklas |
504 |
f.setWriteProtected(false); |
4687 |
26 Feb 18 |
nicklas |
505 |
dc.reattachItem(f, true); // Needed since DELETE permissions is not granted otherwise |
4687 |
26 Feb 18 |
nicklas |
506 |
} |
2685 |
19 Sep 14 |
nicklas |
507 |
f.setRemoved(true); |
2685 |
19 Sep 14 |
nicklas |
508 |
files.add(f); |
2685 |
19 Sep 14 |
nicklas |
509 |
} |
2685 |
19 Sep 14 |
nicklas |
510 |
} |
2685 |
19 Sep 14 |
nicklas |
511 |
|
2685 |
19 Sep 14 |
nicklas |
512 |
return files; |
2685 |
19 Sep 14 |
nicklas |
513 |
} |
2685 |
19 Sep 14 |
nicklas |
514 |
|
4680 |
21 Feb 18 |
nicklas |
515 |
/** |
4680 |
21 Feb 18 |
nicklas |
Mark all directories for removal. |
4680 |
21 Feb 18 |
nicklas |
@since 4.15 |
4680 |
21 Feb 18 |
nicklas |
518 |
*/ |
4680 |
21 Feb 18 |
nicklas |
519 |
public static List<Directory> removeDirectories(DbControl dc, List<File> files) |
4680 |
21 Feb 18 |
nicklas |
520 |
{ |
4680 |
21 Feb 18 |
nicklas |
521 |
List<Directory> directories = new ArrayList<Directory>(); |
4680 |
21 Feb 18 |
nicklas |
522 |
|
4680 |
21 Feb 18 |
nicklas |
523 |
for (File f : files) |
4680 |
21 Feb 18 |
nicklas |
524 |
{ |
4680 |
21 Feb 18 |
nicklas |
525 |
Directory d = f.getDirectory(); |
4680 |
21 Feb 18 |
nicklas |
526 |
if (!d.isRemoved()) |
4680 |
21 Feb 18 |
nicklas |
527 |
{ |
4680 |
21 Feb 18 |
nicklas |
528 |
d.setRemoved(true); |
4680 |
21 Feb 18 |
nicklas |
529 |
directories.add(d); |
4680 |
21 Feb 18 |
nicklas |
530 |
} |
4680 |
21 Feb 18 |
nicklas |
531 |
} |
4680 |
21 Feb 18 |
nicklas |
532 |
return directories; |
4680 |
21 Feb 18 |
nicklas |
533 |
} |
4680 |
21 Feb 18 |
nicklas |
534 |
|
5760 |
26 Nov 19 |
nicklas |
535 |
private static Object configLock = new Object(); |
4306 |
17 Jan 17 |
nicklas |
536 |
private static volatile XmlConfig rootConfig; |
4306 |
17 Jan 17 |
nicklas |
537 |
private static volatile Map<String, XmlConfig> openGridConfig; |
4313 |
20 Jan 17 |
nicklas |
538 |
private static EventHandler reloadConfig; |
6683 |
20 Apr 22 |
nicklas |
539 |
private static java.io.File configFile; |
6683 |
20 Apr 22 |
nicklas |
540 |
private static long configFileLastModifed; |
2685 |
19 Sep 14 |
nicklas |
541 |
|
2859 |
27 Oct 14 |
nicklas |
542 |
/** |
2859 |
27 Oct 14 |
nicklas |
Get Reggie configuration. |
2859 |
27 Oct 14 |
nicklas |
544 |
*/ |
2859 |
27 Oct 14 |
nicklas |
545 |
public static XmlConfig getConfig() |
2859 |
27 Oct 14 |
nicklas |
546 |
{ |
4306 |
17 Jan 17 |
nicklas |
547 |
if (rootConfig == null) loadConfig(false); |
4306 |
17 Jan 17 |
nicklas |
548 |
return rootConfig; |
2859 |
27 Oct 14 |
nicklas |
549 |
} |
2859 |
27 Oct 14 |
nicklas |
550 |
|
2859 |
27 Oct 14 |
nicklas |
551 |
/** |
6735 |
09 May 22 |
nicklas |
Get configuration for the Job cluster with |
4306 |
17 Jan 17 |
nicklas |
the given id. |
4306 |
17 Jan 17 |
nicklas |
554 |
*/ |
4306 |
17 Jan 17 |
nicklas |
555 |
public static XmlConfig getConfig(String hostId) |
4306 |
17 Jan 17 |
nicklas |
556 |
{ |
4306 |
17 Jan 17 |
nicklas |
557 |
if (openGridConfig == null) loadConfig(false); |
4306 |
17 Jan 17 |
nicklas |
558 |
return openGridConfig.get(hostId); |
4306 |
17 Jan 17 |
nicklas |
559 |
} |
4306 |
17 Jan 17 |
nicklas |
560 |
|
4306 |
17 Jan 17 |
nicklas |
561 |
/** |
2859 |
27 Oct 14 |
nicklas |
Force reload the Reggie configuration. |
2859 |
27 Oct 14 |
nicklas |
563 |
*/ |
5760 |
26 Nov 19 |
nicklas |
564 |
public static XmlConfig reloadConfig() |
2859 |
27 Oct 14 |
nicklas |
565 |
{ |
5847 |
27 Feb 20 |
nicklas |
566 |
loadConfig(true); |
5847 |
27 Feb 20 |
nicklas |
567 |
ActivityLog.getInstance().reloadConfig(); |
5847 |
27 Feb 20 |
nicklas |
568 |
CounterService.getInstance().reloadConfig(); |
4306 |
17 Jan 17 |
nicklas |
569 |
return rootConfig; |
2859 |
27 Oct 14 |
nicklas |
570 |
} |
2859 |
27 Oct 14 |
nicklas |
571 |
|
6683 |
20 Apr 22 |
nicklas |
572 |
/** |
6683 |
20 Apr 22 |
nicklas |
Check if the reggie-config.xml file has been modified since |
6683 |
20 Apr 22 |
nicklas |
it was last loaded. |
6683 |
20 Apr 22 |
nicklas |
@since 4.38 |
6683 |
20 Apr 22 |
nicklas |
576 |
*/ |
6683 |
20 Apr 22 |
nicklas |
577 |
public static boolean configIsModified() |
6683 |
20 Apr 22 |
nicklas |
578 |
{ |
6683 |
20 Apr 22 |
nicklas |
579 |
return configFile != null && configFile.lastModified() != configFileLastModifed; |
6683 |
20 Apr 22 |
nicklas |
580 |
} |
6683 |
20 Apr 22 |
nicklas |
581 |
|
5760 |
26 Nov 19 |
nicklas |
582 |
public static void unloadConfig() |
2892 |
04 Nov 14 |
nicklas |
583 |
{ |
5760 |
26 Nov 19 |
nicklas |
584 |
synchronized (configLock) |
4313 |
20 Jan 17 |
nicklas |
585 |
{ |
5760 |
26 Nov 19 |
nicklas |
586 |
rootConfig = null; |
5760 |
26 Nov 19 |
nicklas |
587 |
openGridConfig = null; |
6683 |
20 Apr 22 |
nicklas |
588 |
configFile = null; |
5760 |
26 Nov 19 |
nicklas |
589 |
if (reloadConfig != null) |
5760 |
26 Nov 19 |
nicklas |
590 |
{ |
5760 |
26 Nov 19 |
nicklas |
591 |
Application.getExtensionsManager().getRegistry().unregisterEventHandler(reloadConfig); |
5760 |
26 Nov 19 |
nicklas |
592 |
reloadConfig = null; |
5760 |
26 Nov 19 |
nicklas |
593 |
} |
4313 |
20 Jan 17 |
nicklas |
594 |
} |
2892 |
04 Nov 14 |
nicklas |
595 |
} |
2892 |
04 Nov 14 |
nicklas |
596 |
|
3973 |
26 May 16 |
nicklas |
597 |
/** |
3997 |
14 Jun 16 |
nicklas |
Get an existing session control for REGGIE and check that a user is logged in. |
3973 |
26 May 16 |
nicklas |
@since 4.5 |
3973 |
26 May 16 |
nicklas |
600 |
*/ |
3973 |
26 May 16 |
nicklas |
601 |
public static SessionControl getSessionControl(ServletRequest req) |
3973 |
26 May 16 |
nicklas |
602 |
{ |
3997 |
14 Jun 16 |
nicklas |
603 |
return getSessionControl(req, ClientApp.REGGIE, true); |
3973 |
26 May 16 |
nicklas |
604 |
} |
3973 |
26 May 16 |
nicklas |
605 |
|
3997 |
14 Jun 16 |
nicklas |
606 |
/** |
3997 |
14 Jun 16 |
nicklas |
Get an existing session control and optionally check that a user is logged in. |
3997 |
14 Jun 16 |
nicklas |
@since 4.6 |
3997 |
14 Jun 16 |
nicklas |
609 |
*/ |
3997 |
14 Jun 16 |
nicklas |
610 |
public static SessionControl getSessionControl(ServletRequest req, ClientApp client, boolean checkLoggedIn) |
3997 |
14 Jun 16 |
nicklas |
611 |
{ |
3997 |
14 Jun 16 |
nicklas |
612 |
return Application.getSessionControl(req.getParameter("ID"), client.getExternalId(), req.getRemoteAddr(), checkLoggedIn); |
3997 |
14 Jun 16 |
nicklas |
613 |
} |
3997 |
14 Jun 16 |
nicklas |
614 |
|
3997 |
14 Jun 16 |
nicklas |
615 |
|
5760 |
26 Nov 19 |
nicklas |
616 |
private static Object sessionLock = new Object(); |
3033 |
12 Dec 14 |
nicklas |
617 |
private static SessionControl rootSc; |
3033 |
12 Dec 14 |
nicklas |
618 |
/** |
3033 |
12 Dec 14 |
nicklas |
Get a session control were the root user is logged in and the SCAN-B project |
3033 |
12 Dec 14 |
nicklas |
is active. This method must be given a system session control given out by |
3033 |
12 Dec 14 |
nicklas |
BASE when starting services. The service session control only has permission |
3033 |
12 Dec 14 |
nicklas |
to impersonate another user. This method should be used whenever a service |
3033 |
12 Dec 14 |
nicklas |
needs to access the database. Do not keep the returned session control for |
3033 |
12 Dec 14 |
nicklas |
a long time since it may be closed by other operations. |
3033 |
12 Dec 14 |
nicklas |
625 |
|
3033 |
12 Dec 14 |
nicklas |
Services should not close the returned session control after use, but |
3033 |
12 Dec 14 |
nicklas |
should call {@link #closeRootSessionControl()} when they are stopped. |
3045 |
16 Dec 14 |
nicklas |
@since 3.0 |
3033 |
12 Dec 14 |
nicklas |
629 |
*/ |
5760 |
26 Nov 19 |
nicklas |
630 |
public static SessionControl getRootSessionControl(SessionControl systemSc) |
3033 |
12 Dec 14 |
nicklas |
631 |
{ |
5760 |
26 Nov 19 |
nicklas |
632 |
synchronized (sessionLock) |
3033 |
12 Dec 14 |
nicklas |
633 |
{ |
5760 |
26 Nov 19 |
nicklas |
634 |
if (rootSc == null || rootSc.isClosed()) |
3033 |
12 Dec 14 |
nicklas |
635 |
{ |
5760 |
26 Nov 19 |
nicklas |
636 |
SessionControl tmp = systemSc.impersonateLogin(SystemItems.getId(User.ROOT), "Reggie services"); |
5760 |
26 Nov 19 |
nicklas |
637 |
DbControl dc = tmp.newDbControl(); |
5760 |
26 Nov 19 |
nicklas |
638 |
try |
3033 |
12 Dec 14 |
nicklas |
639 |
{ |
5760 |
26 Nov 19 |
nicklas |
640 |
ItemQuery<Project> q = Project.getQuery(); |
5760 |
26 Nov 19 |
nicklas |
641 |
q.setIncludes(Include.ALL); |
5760 |
26 Nov 19 |
nicklas |
642 |
q.restrict(Restrictions.eq(Hql.property("name"), Expressions.string("SCAN-B"))); |
5760 |
26 Nov 19 |
nicklas |
643 |
List<Project> projects = q.list(dc); |
5760 |
26 Nov 19 |
nicklas |
644 |
if (projects.size() == 1) |
5760 |
26 Nov 19 |
nicklas |
645 |
{ |
5760 |
26 Nov 19 |
nicklas |
646 |
tmp.setActiveProject(projects.get(0)); |
5760 |
26 Nov 19 |
nicklas |
647 |
} |
3033 |
12 Dec 14 |
nicklas |
648 |
} |
5760 |
26 Nov 19 |
nicklas |
649 |
finally |
5760 |
26 Nov 19 |
nicklas |
650 |
{ |
5760 |
26 Nov 19 |
nicklas |
651 |
if (dc != null) dc.close(); |
5760 |
26 Nov 19 |
nicklas |
652 |
} |
5760 |
26 Nov 19 |
nicklas |
653 |
|
5760 |
26 Nov 19 |
nicklas |
// Set active project |
5760 |
26 Nov 19 |
nicklas |
655 |
rootSc = tmp; |
3033 |
12 Dec 14 |
nicklas |
656 |
} |
5760 |
26 Nov 19 |
nicklas |
657 |
else |
3033 |
12 Dec 14 |
nicklas |
658 |
{ |
5760 |
26 Nov 19 |
nicklas |
659 |
rootSc.updateLastAccess(); |
3033 |
12 Dec 14 |
nicklas |
660 |
} |
3033 |
12 Dec 14 |
nicklas |
661 |
} |
3033 |
12 Dec 14 |
nicklas |
662 |
return rootSc; |
3033 |
12 Dec 14 |
nicklas |
663 |
} |
3033 |
12 Dec 14 |
nicklas |
664 |
|
3033 |
12 Dec 14 |
nicklas |
665 |
/** |
3033 |
12 Dec 14 |
nicklas |
Close the root session control if it is active. This method should be |
3033 |
12 Dec 14 |
nicklas |
called from services when they are stopped. |
3045 |
16 Dec 14 |
nicklas |
@since 3.0 |
3033 |
12 Dec 14 |
nicklas |
669 |
*/ |
5760 |
26 Nov 19 |
nicklas |
670 |
public static void closeRootSessionControl() |
3033 |
12 Dec 14 |
nicklas |
671 |
{ |
5760 |
26 Nov 19 |
nicklas |
672 |
synchronized (sessionLock) |
3033 |
12 Dec 14 |
nicklas |
673 |
{ |
5760 |
26 Nov 19 |
nicklas |
674 |
if (rootSc != null) |
5760 |
26 Nov 19 |
nicklas |
675 |
{ |
5760 |
26 Nov 19 |
nicklas |
676 |
rootSc.close(); |
5760 |
26 Nov 19 |
nicklas |
677 |
rootSc = null; |
5760 |
26 Nov 19 |
nicklas |
678 |
} |
3033 |
12 Dec 14 |
nicklas |
679 |
} |
3033 |
12 Dec 14 |
nicklas |
680 |
} |
3033 |
12 Dec 14 |
nicklas |
681 |
|
5760 |
26 Nov 19 |
nicklas |
682 |
private static void loadConfig(boolean force) |
2859 |
27 Oct 14 |
nicklas |
683 |
{ |
2892 |
04 Nov 14 |
nicklas |
684 |
URL configUrl = Reggie.class.getResource("/reggie-config.xml"); |
4306 |
17 Jan 17 |
nicklas |
685 |
if (rootConfig != null && !force) return; |
5760 |
26 Nov 19 |
nicklas |
686 |
synchronized (configLock) |
2859 |
27 Oct 14 |
nicklas |
687 |
{ |
5760 |
26 Nov 19 |
nicklas |
688 |
InputStream is = null; |
5760 |
26 Nov 19 |
nicklas |
689 |
try |
2859 |
27 Oct 14 |
nicklas |
690 |
{ |
5760 |
26 Nov 19 |
nicklas |
691 |
logger.debug("Loading configuration from; " + configUrl); |
5760 |
26 Nov 19 |
nicklas |
692 |
is = configUrl == null ? null : configUrl.openStream(); |
5760 |
26 Nov 19 |
nicklas |
693 |
if (is == null) |
4306 |
17 Jan 17 |
nicklas |
694 |
{ |
5760 |
26 Nov 19 |
nicklas |
695 |
throw new ConfigurationException("Can't find the configuration file. " + |
5760 |
26 Nov 19 |
nicklas |
696 |
"Make sure 'reggie-config.xml' is in the CLASSPATH."); |
5760 |
26 Nov 19 |
nicklas |
697 |
} |
5760 |
26 Nov 19 |
nicklas |
698 |
|
6683 |
20 Apr 22 |
nicklas |
699 |
configFile = null; |
6683 |
20 Apr 22 |
nicklas |
700 |
if (configUrl.getProtocol().equals("file")) |
6683 |
20 Apr 22 |
nicklas |
701 |
{ |
6683 |
20 Apr 22 |
nicklas |
702 |
java.io.File f = new java.io.File(configUrl.getPath()); |
6683 |
20 Apr 22 |
nicklas |
703 |
if (f.exists()) |
6683 |
20 Apr 22 |
nicklas |
704 |
{ |
6683 |
20 Apr 22 |
nicklas |
705 |
configFile = f; |
6683 |
20 Apr 22 |
nicklas |
706 |
configFileLastModifed = configFile.lastModified(); |
6683 |
20 Apr 22 |
nicklas |
707 |
} |
6683 |
20 Apr 22 |
nicklas |
708 |
} |
6683 |
20 Apr 22 |
nicklas |
709 |
|
5760 |
26 Nov 19 |
nicklas |
710 |
Document dom = XmlUtil2.getValidatedXml(configUrl, null); |
5760 |
26 Nov 19 |
nicklas |
711 |
rootConfig = new XmlConfig(dom.getRootElement(), "[reggie]"); |
5760 |
26 Nov 19 |
nicklas |
712 |
openGridConfig = new HashMap<String, XmlConfig>(); |
5760 |
26 Nov 19 |
nicklas |
713 |
|
5760 |
26 Nov 19 |
nicklas |
714 |
OpenGridService ogs = OpenGridService.getInstance(); |
6735 |
09 May 22 |
nicklas |
715 |
if (!ogs.isRunning()) logger.warn("The Job scheduler service is no running"); |
5760 |
26 Nov 19 |
nicklas |
716 |
|
5760 |
26 Nov 19 |
nicklas |
717 |
Element hosts = dom.getRootElement().getChild("remote-hosts"); |
5760 |
26 Nov 19 |
nicklas |
718 |
List<Element> allHosts = hosts.getChildren("host"); |
5760 |
26 Nov 19 |
nicklas |
719 |
for (Element h : allHosts) |
5760 |
26 Nov 19 |
nicklas |
720 |
{ |
5760 |
26 Nov 19 |
nicklas |
721 |
String[] idList = h.getAttributeValue("id").split(","); |
5760 |
26 Nov 19 |
nicklas |
722 |
for (String id : idList) |
5583 |
21 Aug 19 |
nicklas |
723 |
{ |
5760 |
26 Nov 19 |
nicklas |
724 |
if (!ogs.isDefined(id)) |
5760 |
26 Nov 19 |
nicklas |
725 |
{ |
5760 |
26 Nov 19 |
nicklas |
726 |
logger.warn("No cluster defined for id=" + id); |
5760 |
26 Nov 19 |
nicklas |
727 |
} |
5760 |
26 Nov 19 |
nicklas |
728 |
openGridConfig.put(id, new XmlConfig(h, "[" + id + "]")); |
5583 |
21 Aug 19 |
nicklas |
729 |
} |
4306 |
17 Jan 17 |
nicklas |
730 |
} |
5760 |
26 Nov 19 |
nicklas |
731 |
|
4306 |
17 Jan 17 |
nicklas |
732 |
} |
5760 |
26 Nov 19 |
nicklas |
733 |
catch (Exception ex) |
4313 |
20 Jan 17 |
nicklas |
734 |
{ |
5760 |
26 Nov 19 |
nicklas |
735 |
logger.error("Could not load configuration", ex); |
5760 |
26 Nov 19 |
nicklas |
736 |
throw new RuntimeException(ex); |
4313 |
20 Jan 17 |
nicklas |
737 |
} |
5760 |
26 Nov 19 |
nicklas |
738 |
finally |
5760 |
26 Nov 19 |
nicklas |
739 |
{ |
5760 |
26 Nov 19 |
nicklas |
740 |
FileUtil.close(is); |
5760 |
26 Nov 19 |
nicklas |
741 |
} |
2859 |
27 Oct 14 |
nicklas |
742 |
} |
5847 |
27 Feb 20 |
nicklas |
743 |
|
5847 |
27 Feb 20 |
nicklas |
744 |
if (reloadConfig == null) |
5847 |
27 Feb 20 |
nicklas |
745 |
{ |
5847 |
27 Feb 20 |
nicklas |
// Create and register an event handler that re-load the Reggie configuration |
6735 |
09 May 22 |
nicklas |
// whenever a SERVICE_STARTED event is sent for the Job scheduler service |
5847 |
27 Feb 20 |
nicklas |
748 |
Registry registry = Application.getExtensionsManager().getRegistry(); |
5847 |
27 Feb 20 |
nicklas |
749 |
synchronized (registry) |
5847 |
27 Feb 20 |
nicklas |
750 |
{ |
5847 |
27 Feb 20 |
nicklas |
751 |
if (reloadConfig == null) |
5847 |
27 Feb 20 |
nicklas |
752 |
{ |
5847 |
27 Feb 20 |
nicklas |
753 |
reloadConfig = new ReloadConfigEventHandler(); |
5847 |
27 Feb 20 |
nicklas |
754 |
EventFilter whenOpenGridServiceStarted = new ExtensionEventFilter("net.sf.basedb.opengrid.service", Services.SERVICE_STARTED); |
5847 |
27 Feb 20 |
nicklas |
755 |
registry.registerEventHandler(reloadConfig, whenOpenGridServiceStarted, Reggie.class.getClassLoader()); |
5847 |
27 Feb 20 |
nicklas |
756 |
} |
5847 |
27 Feb 20 |
nicklas |
757 |
} |
5847 |
27 Feb 20 |
nicklas |
758 |
} |
2859 |
27 Oct 14 |
nicklas |
759 |
} |
3506 |
23 Sep 15 |
nicklas |
760 |
|
3506 |
23 Sep 15 |
nicklas |
761 |
/** |
3506 |
23 Sep 15 |
nicklas |
Check that the file exists on the local filesystem. |
3506 |
23 Sep 15 |
nicklas |
@since 3.7 |
3506 |
23 Sep 15 |
nicklas |
764 |
*/ |
3506 |
23 Sep 15 |
nicklas |
765 |
public static void checkFile(String path, boolean directory) |
3506 |
23 Sep 15 |
nicklas |
766 |
throws IOException |
3506 |
23 Sep 15 |
nicklas |
767 |
{ |
3506 |
23 Sep 15 |
nicklas |
768 |
java.io.File f = new java.io.File(path); |
3506 |
23 Sep 15 |
nicklas |
769 |
if (directory ? !f.isDirectory() : !f.isFile()) |
3506 |
23 Sep 15 |
nicklas |
770 |
{ |
3506 |
23 Sep 15 |
nicklas |
771 |
throw new FileNotFoundException(path); |
3506 |
23 Sep 15 |
nicklas |
772 |
} |
3506 |
23 Sep 15 |
nicklas |
773 |
} |
2859 |
27 Oct 14 |
nicklas |
774 |
|
4313 |
20 Jan 17 |
nicklas |
775 |
/** |
5885 |
30 Mar 20 |
nicklas |
Get the contents of an internal template file as a text string. |
5885 |
30 Mar 20 |
nicklas |
777 |
*/ |
5885 |
30 Mar 20 |
nicklas |
778 |
public static String getTemplateFile(String path) |
5885 |
30 Mar 20 |
nicklas |
779 |
{ |
5885 |
30 Mar 20 |
nicklas |
780 |
String template = null; |
5885 |
30 Mar 20 |
nicklas |
781 |
InputStream in = null; |
5885 |
30 Mar 20 |
nicklas |
782 |
ByteArrayOutputStream buffer = new ByteArrayOutputStream(2048); |
5885 |
30 Mar 20 |
nicklas |
783 |
try |
5885 |
30 Mar 20 |
nicklas |
784 |
{ |
5885 |
30 Mar 20 |
nicklas |
785 |
in = Reggie.class.getResourceAsStream(path); |
5885 |
30 Mar 20 |
nicklas |
786 |
FileUtil.copy(in, buffer); |
5885 |
30 Mar 20 |
nicklas |
787 |
template = buffer.toString("UTF-8"); |
5885 |
30 Mar 20 |
nicklas |
788 |
} |
5885 |
30 Mar 20 |
nicklas |
789 |
catch (IOException ex) |
5885 |
30 Mar 20 |
nicklas |
790 |
{ |
5885 |
30 Mar 20 |
nicklas |
791 |
throw new RuntimeException(ex); |
5885 |
30 Mar 20 |
nicklas |
792 |
} |
5885 |
30 Mar 20 |
nicklas |
793 |
finally |
5885 |
30 Mar 20 |
nicklas |
794 |
{ |
5885 |
30 Mar 20 |
nicklas |
795 |
FileUtil.close(in); |
5885 |
30 Mar 20 |
nicklas |
796 |
} |
5885 |
30 Mar 20 |
nicklas |
797 |
return template; |
5885 |
30 Mar 20 |
nicklas |
798 |
} |
5885 |
30 Mar 20 |
nicklas |
799 |
|
5885 |
30 Mar 20 |
nicklas |
800 |
|
5885 |
30 Mar 20 |
nicklas |
801 |
/** |
4313 |
20 Jan 17 |
nicklas |
Whenever we recieve an event we unload the Reggie configuration. |
4313 |
20 Jan 17 |
nicklas |
Use an EventFilter when registering this event handler since otherwise |
4313 |
20 Jan 17 |
nicklas |
it will trigger on all events. |
4313 |
20 Jan 17 |
nicklas |
@since 4.9 |
4313 |
20 Jan 17 |
nicklas |
806 |
*/ |
4313 |
20 Jan 17 |
nicklas |
807 |
static class ReloadConfigEventHandler |
4313 |
20 Jan 17 |
nicklas |
808 |
implements EventHandler |
4313 |
20 Jan 17 |
nicklas |
809 |
{ |
4313 |
20 Jan 17 |
nicklas |
810 |
ReloadConfigEventHandler() |
4313 |
20 Jan 17 |
nicklas |
811 |
{} |
3506 |
23 Sep 15 |
nicklas |
812 |
|
4313 |
20 Jan 17 |
nicklas |
813 |
@Override |
4313 |
20 Jan 17 |
nicklas |
814 |
public void handleEvent(EventType event, ExtensionPoint<?> extensionPoint, Extension<?> extension) |
4313 |
20 Jan 17 |
nicklas |
815 |
{ |
4313 |
20 Jan 17 |
nicklas |
816 |
if (logger.isDebugEnabled()) |
4313 |
20 Jan 17 |
nicklas |
817 |
{ |
4313 |
20 Jan 17 |
nicklas |
818 |
logger.debug(extension + ": " + event + "; reloading reggie config"); |
4313 |
20 Jan 17 |
nicklas |
819 |
} |
4313 |
20 Jan 17 |
nicklas |
820 |
Reggie.reloadConfig(); |
4313 |
20 Jan 17 |
nicklas |
821 |
} |
4313 |
20 Jan 17 |
nicklas |
822 |
} |
4313 |
20 Jan 17 |
nicklas |
823 |
|
1282 |
25 Jan 11 |
nicklas |
824 |
} |