extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/Reggie.java

Code
Comments
Other
Rev Date Author Line
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 66   Global constants for the Reggie package.
1282 25 Jan 11 nicklas 67   @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 75     The current version of this package. Calling toString() to ensure that
6837 05 Sep 22 nicklas 76     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 81     Default converter for date values to string values: yyyyMMdd
1524 25 Jan 12 nicklas 82     @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 87     Alternate converter for date values with a '-' separator: yyyy-MM-dd 
3824 04 Apr 16 nicklas 88     @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 93     Default converter for string values to date values: yyyyMMdd
1524 25 Jan 12 nicklas 94     @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 99     Alternate converter for date values with a '-' separator: yyyy-MM-dd 
5262 24 Jan 19 nicklas 100     @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 106     Default converter for date+time values to string values: yyyyMMdd HHmm
1524 25 Jan 12 nicklas 107     @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 112     Default converter for date+time (with seconds) values to string values: yyyyMMdd HHmmss
4404 17 Mar 17 nicklas 113     @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 118     Alternate converter for date+time values with separators: yyyy-MM-dd HH:mm
3939 16 May 16 nicklas 119     @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 124     Alternate converter for time values with separators: HH:mm
5423 13 May 19 nicklas 125     @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 130     Default converter for string values to date+time values: yyyyMMdd HHmm
1524 25 Jan 12 nicklas 131     @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 136     Include options to make a query only return items in the currently active project.
1560 14 Mar 12 nicklas 137     Use with {@link ItemQuery#setIncludes(java.util.Collection)}
1560 14 Mar 12 nicklas 138     @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 143     Include options to make a query only return items shared to the currently
4000 17 Jun 16 nicklas 144     logged in user.
4000 17 Jun 16 nicklas 145     Use with {@link ItemQuery#setIncludes(java.util.Collection)}
4000 17 Jun 16 nicklas 146     @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 149   //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 152     Regular expression pattern that can be match against a string to see
1827 07 Feb 13 nicklas 153     if it contains a case name, eg. it starts with 7 digits, optionally
6964 19 Dec 22 nicklas 154     followed by a dot and suffixes
1827 07 Feb 13 nicklas 155     @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 160     Path to the directory on the BASE file system where secondary analysis files
2578 15 Aug 14 nicklas 161     are saved. This directory maps some files to the "project-archive" directory 
2578 15 Aug 14 nicklas 162     on the file server.
2578 15 Aug 14 nicklas 163     @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 168     Path to the directory on the BASE file system where secondary analysis files
3600 13 Nov 15 nicklas 169     from external samples are saved. This directory maps some files to the 
3600 13 Nov 15 nicklas 170     "external-archive" directory on the file server.
3600 13 Nov 15 nicklas 171     @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 176     Path to the directory on the BASE file system where reports delivered to external
4028 26 Jul 16 nicklas 177     sites are stored.
4028 26 Jul 16 nicklas 178     @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 183     Path to the directory on the BASE file system where frozen tissue CSV files are expected
4512 31 May 17 nicklas 184     to be stored.
4512 31 May 17 nicklas 185     @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 190     Path to the directory on the BASE file system where import
5397 03 May 19 nicklas 191     files for MIPs aliquot plates are expected.
5397 03 May 19 nicklas 192     @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 197     Path to the directory on the BASE file system where import
7139 27 Apr 23 nicklas 198     files for transport boxes are expected.
7139 27 Apr 23 nicklas 199     @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 205     Path to the directory on the BASE file system where additional template files are
5889 06 Apr 20 nicklas 206     stored.
5889 06 Apr 20 nicklas 207     @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 212     Path to the directory on the BASE file system where referral ID log files are stored.
6277 03 Jun 21 nicklas 213     @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 219     Path to the directory on the BASE file system where files associated with
5892 07 Apr 20 nicklas 220     external library plates are stored.
5892 07 Apr 20 nicklas 221     @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 226     Path to the directory on the BASE file system where JSON files with metadata
6960 13 Dec 22 nicklas 227     about externally processed samples are saved.
6960 13 Dec 22 nicklas 228     @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 233     This ID is used on Sample outtake lists.
4138 29 Sep 16 nicklas 234     @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 240     List all annotation types with the given name.
1463 14 Nov 11 martin 241     @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 252     Compare two comparable objects with null safety. Two null objects
1672 30 May 12 nicklas 253     are considered equal and all null objects are sorted after all non-null
1672 30 May 12 nicklas 254     objects.
1672 30 May 12 nicklas 255     @return A negative value if the first argument should be sorted before the second,
1672 30 May 12 nicklas 256       zero if they are equal, a positive value if the second argument should be sorted 
1672 30 May 12 nicklas 257       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 280     Return the first non-null value. If all
3309 06 May 15 nicklas 281     values are null, null is returned.
3309 06 May 15 nicklas 282     @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 298     Join texts parts and make sure a period is ending each sentence.
6389 15 Sep 21 nicklas 299     @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 321     Round a floating point value to a given number of decimals.
1975 15 May 13 nicklas 322     @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 331     Convert to lower case and remove all characters not in [a-z0-9_]
2386 25 Apr 14 nicklas 332     @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 340     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 342     @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 377     Convert a data files folder to a BASE file system folder. 
2801 13 Oct 14 nicklas 378     We want to use a prefix in the BASE file system to prevent
2801 13 Oct 14 nicklas 379     several thousands of subfolders inside a single folder.
2801 13 Oct 14 nicklas 380     The prefix should only be used if the data folder starts with
2801 13 Oct 14 nicklas 381     digits and is two levels deep. The first level is the first two
2801 13 Oct 14 nicklas 382     digits and the second level is the first four digits.
2801 13 Oct 14 nicklas 383     
4551 03 Jul 17 nicklas 384     Note that it must handle both the case when the dataFilesFolder
4551 03 Jul 17 nicklas 385     already have a site prefix and when it hasn't.
4551 03 Jul 17 nicklas 386     
2801 13 Oct 14 nicklas 387     Examples:
2801 13 Oct 14 nicklas 388       /1234567.1/l.r.m.c.lib.g --> /12/1234/1234567.1/l.r.m.c.lib.g
4551 03 Jul 17 nicklas 389       /12/1234567.1/l.r.m.c.lib.g --> /12/1234/1234567.1/l.r.m.c.lib.g
2801 13 Oct 14 nicklas 390       /debug/1234567.1/l.r.m.c.lib.g --> /debug/1234567.1/l.r.m.c.lib.g
2801 13 Oct 14 nicklas 391       /Stratagene/r.m.c.lib.g --> /Stratagene/r.m.c.lib.g
2801 13 Oct 14 nicklas 392       /SKBR3/m.c.lib.g --> /SKBR3/m.c.lib.g
3600 13 Nov 15 nicklas 393       /NN/K562/m.c.lib.g --> /NN/K562/m.c.lib.g
2801 13 Oct 14 nicklas 394     @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 398     // If the path starts with '/'+7 digits+'.'+at least one more digit or 'b' +'/'
4551 03 Jul 17 nicklas 399     // insert prefix based on first 2+4 digits 
4551 03 Jul 17 nicklas 400     // (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 405     Check if an item with the given name is an external item.
5553 12 Aug 19 nicklas 406     @param name If the name starts with only digits the item 
5553 12 Aug 19 nicklas 407       is not external and this method return false
5553 12 Aug 19 nicklas 408     @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 416     For an external item, get the group name that should have
5594 11 Sep 19 nicklas 417     read access to files that are created on the file server 
5594 11 Sep 19 nicklas 418     (ExternalArchive). The returned group name should be used
5594 11 Sep 19 nicklas 419     with a 'chgrp <group> <file-or-folder>' command.
5594 11 Sep 19 nicklas 420     
5594 11 Sep 19 nicklas 421     Group names are linked to prefixes used on external items.
5594 11 Sep 19 nicklas 422     in reggie-config.xml:
5594 11 Sep 19 nicklas 423     
5594 11 Sep 19 nicklas 424     <external-samples>
5594 11 Sep 19 nicklas 425       <groupname prefix="..">...</groupname>
5594 11 Sep 19 nicklas 426     </external-samples>
5594 11 Sep 19 nicklas 427     
5594 11 Sep 19 nicklas 428     The prefix is extracted from the given name by taking all
5594 11 Sep 19 nicklas 429     characters before the first underscore (_). For example,
5594 11 Sep 19 nicklas 430     'NN_foobar.lib.g' --> 'NN'.
5594 11 Sep 19 nicklas 431     
5594 11 Sep 19 nicklas 432     @return A group name, or null if the name has no prefix or 
5594 11 Sep 19 nicklas 433       if no group has been configured
5594 11 Sep 19 nicklas 434     @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 450     Remove the prefix from the name. A prefix is a
5524 24 Jun 19 nicklas 451     number of letters/numbers followed by an underscore.
5524 24 Jun 19 nicklas 452     @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 461     Get the prefix from the name. A prefix is a
5930 06 May 20 nicklas 462     number of letters/numbers followed by an underscore.
5930 06 May 20 nicklas 463     Returns null if the name has no prefix.
5930 06 May 20 nicklas 464     @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 473     Mark all related files for removal.
2685 19 Sep 14 nicklas 474     @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 516     Mark all directories for removal.
4680 21 Feb 18 nicklas 517     @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 543     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 552     Get configuration for the Job cluster with
4306 17 Jan 17 nicklas 553     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 562     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 573     Check if the reggie-config.xml file has been modified since
6683 20 Apr 22 nicklas 574     it was last loaded.
6683 20 Apr 22 nicklas 575     @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 598     Get an existing session control for REGGIE and check that a user is logged in.
3973 26 May 16 nicklas 599     @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 607     Get an existing session control and optionally check that a user is logged in.
3997 14 Jun 16 nicklas 608     @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 619     Get a session control were the root user is logged in and the SCAN-B project
3033 12 Dec 14 nicklas 620     is active. This method must be given a system session control given out by
3033 12 Dec 14 nicklas 621     BASE when starting services. The service session control only has permission
3033 12 Dec 14 nicklas 622     to impersonate another user. This method should be used whenever a service
3033 12 Dec 14 nicklas 623     needs to access the database. Do not keep the returned session control for 
3033 12 Dec 14 nicklas 624     a long time since it may be closed by other operations. 
3033 12 Dec 14 nicklas 625     
3033 12 Dec 14 nicklas 626     Services should  not close the returned session control after use, but
3033 12 Dec 14 nicklas 627     should call {@link #closeRootSessionControl()} when they are stopped.
3045 16 Dec 14 nicklas 628     @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 654         // 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 666     Close the root session control if it is active. This method should be
3033 12 Dec 14 nicklas 667     called from services when they are stopped.
3045 16 Dec 14 nicklas 668     @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 746       // Create and register an event handler that re-load the Reggie configuration
6735 09 May 22 nicklas 747       // 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 762     Check that the file exists on the local filesystem.
3506 23 Sep 15 nicklas 763     @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 776     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 802     Whenever we recieve an event we unload the Reggie configuration.
4313 20 Jan 17 nicklas 803     Use an EventFilter when registering this event handler since otherwise
4313 20 Jan 17 nicklas 804     it will trigger on all events.
4313 20 Jan 17 nicklas 805     @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 }