extensions/net.sf.basedb.relax/trunk/src/net/sf/basedb/relax/servlet/InstallServlet.java

Code
Comments
Other
Rev Date Author Line
4350 10 Feb 17 nicklas 1 package net.sf.basedb.relax.servlet;
4350 10 Feb 17 nicklas 2
4350 10 Feb 17 nicklas 3 import java.io.IOException;
4406 20 Mar 17 nicklas 4 import java.net.URI;
5176 05 Dec 18 nicklas 5 import java.util.ArrayList;
5176 05 Dec 18 nicklas 6 import java.util.Arrays;
4406 20 Mar 17 nicklas 7 import java.util.Collections;
4406 20 Mar 17 nicklas 8 import java.util.HashMap;
4353 13 Feb 17 nicklas 9 import java.util.List;
4406 20 Mar 17 nicklas 10 import java.util.Map;
4406 20 Mar 17 nicklas 11 import java.util.Set;
4350 10 Feb 17 nicklas 12
4350 10 Feb 17 nicklas 13 import javax.servlet.ServletException;
4350 10 Feb 17 nicklas 14 import javax.servlet.http.HttpServlet;
4350 10 Feb 17 nicklas 15 import javax.servlet.http.HttpServletRequest;
4350 10 Feb 17 nicklas 16 import javax.servlet.http.HttpServletResponse;
4350 10 Feb 17 nicklas 17
4350 10 Feb 17 nicklas 18 import org.json.simple.JSONArray;
4350 10 Feb 17 nicklas 19 import org.json.simple.JSONObject;
4350 10 Feb 17 nicklas 20
5176 05 Dec 18 nicklas 21 import net.sf.basedb.core.AnnotationType;
5177 05 Dec 18 nicklas 22 import net.sf.basedb.core.AnnotationTypeCategory;
4350 10 Feb 17 nicklas 23 import net.sf.basedb.core.DbControl;
4406 20 Mar 17 nicklas 24 import net.sf.basedb.core.Directory;
4406 20 Mar 17 nicklas 25 import net.sf.basedb.core.FileServer;
4406 20 Mar 17 nicklas 26 import net.sf.basedb.core.Group;
5177 05 Dec 18 nicklas 27 import net.sf.basedb.core.Include;
4353 13 Feb 17 nicklas 28 import net.sf.basedb.core.Item;
4406 20 Mar 17 nicklas 29 import net.sf.basedb.core.ItemKey;
4514 01 Jun 17 nicklas 30 import net.sf.basedb.core.ItemNotFoundException;
5177 05 Dec 18 nicklas 31 import net.sf.basedb.core.ItemQuery;
4353 13 Feb 17 nicklas 32 import net.sf.basedb.core.ItemSubtype;
4406 20 Mar 17 nicklas 33 import net.sf.basedb.core.MultiPermissions;
4406 20 Mar 17 nicklas 34 import net.sf.basedb.core.Path;
4406 20 Mar 17 nicklas 35 import net.sf.basedb.core.Permission;
4735 05 Apr 18 nicklas 36 import net.sf.basedb.core.Platform;
4735 05 Apr 18 nicklas 37 import net.sf.basedb.core.PlatformVariant;
4514 01 Jun 17 nicklas 38 import net.sf.basedb.core.PluginDefinition;
4406 20 Mar 17 nicklas 39 import net.sf.basedb.core.Project;
4406 20 Mar 17 nicklas 40 import net.sf.basedb.core.ProjectKey;
4515 01 Jun 17 nicklas 41 import net.sf.basedb.core.RawDataType;
4515 01 Jun 17 nicklas 42 import net.sf.basedb.core.RawDataTypes;
4350 10 Feb 17 nicklas 43 import net.sf.basedb.core.SessionControl;
4406 20 Mar 17 nicklas 44 import net.sf.basedb.core.SharedItem;
4406 20 Mar 17 nicklas 45 import net.sf.basedb.core.SystemItems;
5177 05 Dec 18 nicklas 46 import net.sf.basedb.core.Type;
5177 05 Dec 18 nicklas 47 import net.sf.basedb.core.query.Expressions;
5177 05 Dec 18 nicklas 48 import net.sf.basedb.core.query.Hql;
5177 05 Dec 18 nicklas 49 import net.sf.basedb.core.query.Restrictions;
4350 10 Feb 17 nicklas 50 import net.sf.basedb.relax.JsonUtil;
4350 10 Feb 17 nicklas 51 import net.sf.basedb.relax.Relax;
4608 03 Oct 17 nicklas 52 import net.sf.basedb.relax.ServerMode;
5176 05 Dec 18 nicklas 53 import net.sf.basedb.relax.dao.Annotationtype;
4406 20 Mar 17 nicklas 54 import net.sf.basedb.relax.dao.Fileserver;
4735 05 Apr 18 nicklas 55 import net.sf.basedb.relax.dao.Rawdatatype;
4353 13 Feb 17 nicklas 56 import net.sf.basedb.relax.dao.Subtype;
4350 10 Feb 17 nicklas 57 import net.sf.basedb.util.error.ThrowableUtil;
4406 20 Mar 17 nicklas 58 import net.sf.basedb.util.uri.ConnectionManager;
4406 20 Mar 17 nicklas 59 import net.sf.basedb.util.uri.ConnectionManagerFactory;
4406 20 Mar 17 nicklas 60 import net.sf.basedb.util.uri.ConnectionManagerUtil;
4406 20 Mar 17 nicklas 61 import net.sf.basedb.util.uri.ConnectionParameters;
4406 20 Mar 17 nicklas 62 import net.sf.basedb.util.uri.UriMetadata;
4350 10 Feb 17 nicklas 63
4350 10 Feb 17 nicklas 64 /**
4350 10 Feb 17 nicklas 65   Servlet that verify and install items that are required by 
4350 10 Feb 17 nicklas 66   other Relax actions.
4350 10 Feb 17 nicklas 67   
4350 10 Feb 17 nicklas 68   @author nicklas
4350 10 Feb 17 nicklas 69   @since 1.0
4350 10 Feb 17 nicklas 70 */
4350 10 Feb 17 nicklas 71 public class InstallServlet 
4350 10 Feb 17 nicklas 72   extends HttpServlet 
4350 10 Feb 17 nicklas 73 {
4350 10 Feb 17 nicklas 74
4350 10 Feb 17 nicklas 75
4350 10 Feb 17 nicklas 76   private static final long serialVersionUID = -1102755485743652012L;
4350 10 Feb 17 nicklas 77
4350 10 Feb 17 nicklas 78   public InstallServlet()
4350 10 Feb 17 nicklas 79   {}
4350 10 Feb 17 nicklas 80
4350 10 Feb 17 nicklas 81   @Override
4350 10 Feb 17 nicklas 82   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
4350 10 Feb 17 nicklas 83     throws ServletException, IOException 
4350 10 Feb 17 nicklas 84   {
4350 10 Feb 17 nicklas 85     String cmd = req.getParameter("cmd");
4350 10 Feb 17 nicklas 86     JsonUtil.setJsonResponseHeaders(resp);
4350 10 Feb 17 nicklas 87     
4350 10 Feb 17 nicklas 88     JSONObject json = new JSONObject();
4350 10 Feb 17 nicklas 89     json.put("status", "ok");
4350 10 Feb 17 nicklas 90   
4350 10 Feb 17 nicklas 91     final SessionControl sc = Relax.getSessionControl(req);
4350 10 Feb 17 nicklas 92     DbControl dc = null;
5079 08 Nov 18 nicklas 93     String progressId = null;
4350 10 Feb 17 nicklas 94     try
4350 10 Feb 17 nicklas 95     {
4350 10 Feb 17 nicklas 96       if ("Validate".equals(cmd) || "Install".equals(cmd))
4350 10 Feb 17 nicklas 97       {
4632 22 Nov 17 nicklas 98         Relax.checkIsAdmin(sc, "'" + cmd + "' wizard");
4632 22 Nov 17 nicklas 99
5556 13 Aug 19 nicklas 100         Relax.reloadConfig();
5556 13 Aug 19 nicklas 101         
6779 17 Jun 22 nicklas 102         dc = sc.newDbControl("Relax: install");
4632 22 Nov 17 nicklas 103         
4350 10 Feb 17 nicklas 104         boolean createIfMissing = "Install".equals(cmd);
4350 10 Feb 17 nicklas 105         JSONArray jsonChecks = new JSONArray();
4350 10 Feb 17 nicklas 106         
4514 01 Jun 17 nicklas 107         Group everyone = Group.getById(dc, SystemItems.getId(Group.EVERYONE));
4514 01 Jun 17 nicklas 108
4406 20 Mar 17 nicklas 109         // READ permission for the EVERYONE group
4406 20 Mar 17 nicklas 110         PermissionOptions everyoneRead = new PermissionOptions();
4514 01 Jun 17 nicklas 111         everyoneRead.set(everyone, Permission.READ);
4406 20 Mar 17 nicklas 112
4514 01 Jun 17 nicklas 113         PermissionOptions everyoneDenied = new PermissionOptions();
4514 01 Jun 17 nicklas 114         everyoneDenied.set(everyone, null);
4514 01 Jun 17 nicklas 115
4353 13 Feb 17 nicklas 116         // Subtype checks
4353 13 Feb 17 nicklas 117         jsonChecks.add(checkSubtype(dc, Subtype.PATIENT, createIfMissing));
5109 19 Nov 18 nicklas 118         jsonChecks.add(checkSubtype(dc, Subtype.RETRACT, createIfMissing));
5109 19 Nov 18 nicklas 119         jsonChecks.add(checkSubtype(dc, Subtype.NO, createIfMissing));
5109 19 Nov 18 nicklas 120         jsonChecks.add(checkSubtype(dc, Subtype.NOT_ASKED, createIfMissing));
4353 13 Feb 17 nicklas 121         jsonChecks.add(checkSubtype(dc, Subtype.CASE, createIfMissing));
4353 13 Feb 17 nicklas 122         jsonChecks.add(checkSubtype(dc, Subtype.SPECIMEN, createIfMissing));
5134 21 Nov 18 nicklas 123         jsonChecks.add(checkSubtype(dc, Subtype.NO_SPECIMEN, createIfMissing));
5109 19 Nov 18 nicklas 124         jsonChecks.add(checkSubtype(dc, Subtype.BLOOD, createIfMissing));
5109 19 Nov 18 nicklas 125         jsonChecks.add(checkSubtype(dc, Subtype.BLOOD_DNA, createIfMissing));
5977 24 Jun 20 nicklas 126         jsonChecks.add(checkSubtype(dc, Subtype.LYSATE, createIfMissing));
4353 13 Feb 17 nicklas 127         jsonChecks.add(checkSubtype(dc, Subtype.RNA, createIfMissing));
5109 19 Nov 18 nicklas 128         jsonChecks.add(checkSubtype(dc, Subtype.DNA, createIfMissing));
5109 19 Nov 18 nicklas 129         jsonChecks.add(checkSubtype(dc, Subtype.FLOW_THROUGH, createIfMissing));
4353 13 Feb 17 nicklas 130         jsonChecks.add(checkSubtype(dc, Subtype.LIBRARY, createIfMissing));
4400 16 Mar 17 nicklas 131         jsonChecks.add(checkSubtype(dc, Subtype.MERGED_SEQUENCES, createIfMissing));
7008 25 Jan 23 nicklas 132         jsonChecks.add(checkSubtype(dc, Subtype.METHYLATION, createIfMissing));
4409 20 Mar 17 nicklas 133         
4409 20 Mar 17 nicklas 134         jsonChecks.add(checkSubtype(dc, Subtype.SEQUENCE_DATA, createIfMissing));
4409 20 Mar 17 nicklas 135         jsonChecks.add(checkSubtype(dc, Subtype.RAW_DATA, createIfMissing));
5874 23 Mar 20 nicklas 136         jsonChecks.add(checkSubtype(dc, Subtype.VARIANT_CALL_FORMAT, createIfMissing));
7015 26 Jan 23 nicklas 137         jsonChecks.add(checkSubtype(dc, Subtype.IDAT, createIfMissing));
7015 26 Jan 23 nicklas 138         jsonChecks.add(checkSubtype(dc, Subtype.GTC, createIfMissing));
4406 20 Mar 17 nicklas 139
5176 05 Dec 18 nicklas 140         jsonChecks.add(checkAnnotationType(dc, Annotationtype.FIRST_RELEASED_IN, 
5176 05 Dec 18 nicklas 141           // List of current releases -- new ones are added automatically by the release importer
5176 05 Dec 18 nicklas 142           new ValueOptions("2.3", "2.4", "3.0", "3.1", "4.0"), 
5176 05 Dec 18 nicklas 143           createIfMissing, everyoneRead));
5176 05 Dec 18 nicklas 144         
5177 05 Dec 18 nicklas 145         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.PATIENT, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 146         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.RETRACT, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 147         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.NO, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 148         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.NOT_ASKED, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 149         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.CASE, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 150         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.SPECIMEN, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 151         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.NO_SPECIMEN, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 152         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.BLOOD, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 153         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.BLOOD_DNA, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 154         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.LYSATE, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 155         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.RNA, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 156         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.DNA, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 157         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.FLOW_THROUGH, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 158         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.LIBRARY, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 159         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.MERGED_SEQUENCES, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
7008 25 Jan 23 nicklas 160         jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.METHYLATION, createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5241 17 Jan 19 nicklas 161         jsonChecks.add(checkAnnotationTypeCategory(dc, Rawdatatype.CUFFLINKS.getName(), createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5241 17 Jan 19 nicklas 162         jsonChecks.add(checkAnnotationTypeCategory(dc, Rawdatatype.STRINGTIE.getName(), createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5874 23 Mar 20 nicklas 163         jsonChecks.add(checkAnnotationTypeCategory(dc, Rawdatatype.VARIANT_CALL.getName(), createIfMissing, Annotationtype.FIRST_RELEASED_IN));
7008 25 Jan 23 nicklas 164         jsonChecks.add(checkAnnotationTypeCategory(dc, Rawdatatype.ONCOARRAY_500K.getName(), createIfMissing, Annotationtype.FIRST_RELEASED_IN));
5177 05 Dec 18 nicklas 165         
4515 01 Jun 17 nicklas 166         // Raw data types
4515 01 Jun 17 nicklas 167         jsonChecks.add(checkRawDataType(dc, "cufflinks"));
4735 05 Apr 18 nicklas 168
4735 05 Apr 18 nicklas 169         // Platform
4735 05 Apr 18 nicklas 170         jsonChecks.add(checkPlatform(dc, Rawdatatype.STRINGTIE, createIfMissing));
5874 23 Mar 20 nicklas 171         jsonChecks.add(checkPlatform(dc, Rawdatatype.VARIANT_CALL, createIfMissing));
7008 25 Jan 23 nicklas 172         jsonChecks.add(checkPlatform(dc, Rawdatatype.ONCOARRAY_500K, createIfMissing));
4735 05 Apr 18 nicklas 173
4515 01 Jun 17 nicklas 174         
4406 20 Mar 17 nicklas 175         // File servers
4608 03 Oct 17 nicklas 176         if (Relax.getServerMode() == ServerMode.RELAX)
4608 03 Oct 17 nicklas 177         {
4608 03 Oct 17 nicklas 178           // The release archive is only installed on the RELAX server
4608 03 Oct 17 nicklas 179           jsonChecks.add(checkFileServer(dc, Fileserver.RELEASE_ARCHIVE, createIfMissing, everyoneRead));
4608 03 Oct 17 nicklas 180         }
4578 19 Sep 17 nicklas 181         jsonChecks.add(checkFileServer(dc, Fileserver.LEVEL3_ARCHIVE, createIfMissing, everyoneRead));
4350 10 Feb 17 nicklas 182         
4406 20 Mar 17 nicklas 183         // Directory checks
4406 20 Mar 17 nicklas 184         jsonChecks.add(checkDirectory(dc, Relax.RELEASE_DIR, createIfMissing, everyoneRead));
4406 20 Mar 17 nicklas 185
4514 01 Jun 17 nicklas 186         // The PackedFileExporterPlugin should not be available to EVERYONE
4514 01 Jun 17 nicklas 187         jsonChecks.add(checkDisabledPlugin(dc, "net.sf.basedb.plugins.PackedFileExporter", everyoneDenied, createIfMissing));
4514 01 Jun 17 nicklas 188         
4353 13 Feb 17 nicklas 189         json.put("checks", jsonChecks);
4350 10 Feb 17 nicklas 190         
4350 10 Feb 17 nicklas 191         if (createIfMissing) 
4350 10 Feb 17 nicklas 192         {
4350 10 Feb 17 nicklas 193           dc.commit();
4350 10 Feb 17 nicklas 194         }
4350 10 Feb 17 nicklas 195       }
4350 10 Feb 17 nicklas 196     }
4350 10 Feb 17 nicklas 197     catch (Throwable t)
4350 10 Feb 17 nicklas 198     {
4350 10 Feb 17 nicklas 199       t.printStackTrace();
4350 10 Feb 17 nicklas 200       json.clear();
4350 10 Feb 17 nicklas 201       json.put("status", "error");
4350 10 Feb 17 nicklas 202       json.put("message", t.getMessage());
4350 10 Feb 17 nicklas 203       json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
4350 10 Feb 17 nicklas 204     }
4350 10 Feb 17 nicklas 205     finally
4350 10 Feb 17 nicklas 206     {
4350 10 Feb 17 nicklas 207       if (dc != null) dc.close();
5079 08 Nov 18 nicklas 208       if (sc != null && progressId != null) sc.setSessionSetting(progressId, null);
4350 10 Feb 17 nicklas 209       json.writeJSONString(resp.getWriter());
4350 10 Feb 17 nicklas 210     }
4350 10 Feb 17 nicklas 211   }
4350 10 Feb 17 nicklas 212   
4353 13 Feb 17 nicklas 213   /**
4353 13 Feb 17 nicklas 214     Create a subtype with the given options. The subtype is created in
4353 13 Feb 17 nicklas 215     a separate transaction.
4353 13 Feb 17 nicklas 216   */
4353 13 Feb 17 nicklas 217   public ItemSubtype createSubtype(SessionControl sc, Subtype def, Subtype... relatedTo)
4353 13 Feb 17 nicklas 218   {
4353 13 Feb 17 nicklas 219     ItemSubtype subtype = null;
6779 17 Jun 22 nicklas 220     DbControl dc = sc.newDbControl("Relax: install");
4353 13 Feb 17 nicklas 221     try
4353 13 Feb 17 nicklas 222     {
4353 13 Feb 17 nicklas 223       subtype = ItemSubtype.getNew(dc, def.getMainType());
4353 13 Feb 17 nicklas 224       subtype.setName(def.getName());
4353 13 Feb 17 nicklas 225       subtype.setPushAnnotations(def.getPushAnnotations());
4353 13 Feb 17 nicklas 226       
4353 13 Feb 17 nicklas 227       if (relatedTo != null)
4353 13 Feb 17 nicklas 228       {
4353 13 Feb 17 nicklas 229         for (Subtype related : relatedTo)
4353 13 Feb 17 nicklas 230         {
4353 13 Feb 17 nicklas 231           ItemSubtype r = related.get(dc);
4353 13 Feb 17 nicklas 232           if (r != null) subtype.setRelatedSubtype(r);
4353 13 Feb 17 nicklas 233         }
4353 13 Feb 17 nicklas 234       }
4353 13 Feb 17 nicklas 235       
4353 13 Feb 17 nicklas 236       dc.saveItem(subtype);
4353 13 Feb 17 nicklas 237       dc.commit();
4353 13 Feb 17 nicklas 238     }
4353 13 Feb 17 nicklas 239     finally
4353 13 Feb 17 nicklas 240     {
4353 13 Feb 17 nicklas 241       if (dc != null) dc.close();
4353 13 Feb 17 nicklas 242     }
4353 13 Feb 17 nicklas 243     return subtype;
4353 13 Feb 17 nicklas 244   }
4353 13 Feb 17 nicklas 245
4353 13 Feb 17 nicklas 246   /**
4353 13 Feb 17 nicklas 247     Check for an existing item subtype with the given options.
4353 13 Feb 17 nicklas 248     A JSONObject is returned with the result. The following 
4353 13 Feb 17 nicklas 249     keys are used:
4353 13 Feb 17 nicklas 250     <ul>
4353 13 Feb 17 nicklas 251     <li>itemType: ITEMSUBTYPE
4353 13 Feb 17 nicklas 252     <li>name: The name of the subtype
4353 13 Feb 17 nicklas 253     <li>id: The id of the subtype if it exists
4353 13 Feb 17 nicklas 254     <li>mainType: The main item type that the subtype applies to
4353 13 Feb 17 nicklas 255     <li>status: ok, error, or missing
4353 13 Feb 17 nicklas 256     <li>message: A descriptive message in case of an error
4353 13 Feb 17 nicklas 257     </ul
4353 13 Feb 17 nicklas 258   */
4353 13 Feb 17 nicklas 259   public JSONObject checkSubtype(DbControl dc, Subtype subtype, 
4353 13 Feb 17 nicklas 260     boolean createIfMissing, Subtype... relatedTo)
4353 13 Feb 17 nicklas 261   {
4353 13 Feb 17 nicklas 262   
4353 13 Feb 17 nicklas 263     JSONObject json = new JSONObject();
4353 13 Feb 17 nicklas 264     JSONArray jsonMessages = new JSONArray();
4353 13 Feb 17 nicklas 265     json.put("itemType", Item.ITEMSUBTYPE.name());
4353 13 Feb 17 nicklas 266     json.put("name", subtype.getName());
4353 13 Feb 17 nicklas 267     json.put("mainType", subtype.getMainType().name());
4353 13 Feb 17 nicklas 268       
4353 13 Feb 17 nicklas 269     List<ItemSubtype> result = subtype.list(dc);
4353 13 Feb 17 nicklas 270     if (result.size() == 0)
4353 13 Feb 17 nicklas 271     {
4353 13 Feb 17 nicklas 272       if (createIfMissing)
4353 13 Feb 17 nicklas 273       {
4353 13 Feb 17 nicklas 274         ItemSubtype s = createSubtype(dc.getSessionControl(), subtype, relatedTo);
4353 13 Feb 17 nicklas 275         json.put("id", s.getId());
4353 13 Feb 17 nicklas 276         json.put("status", "ok");
4353 13 Feb 17 nicklas 277         jsonMessages.add("Created");
4353 13 Feb 17 nicklas 278       }
4353 13 Feb 17 nicklas 279       else
4353 13 Feb 17 nicklas 280       {
4353 13 Feb 17 nicklas 281         json.put("status", "missing");
4353 13 Feb 17 nicklas 282         jsonMessages.add("Not found");
4353 13 Feb 17 nicklas 283       }
4353 13 Feb 17 nicklas 284     }
4353 13 Feb 17 nicklas 285     else if (result.size() > 1)
4353 13 Feb 17 nicklas 286     {
4353 13 Feb 17 nicklas 287       json.put("status", "error");
4353 13 Feb 17 nicklas 288       jsonMessages.add("Found > 1 subtype");
4353 13 Feb 17 nicklas 289     }
4353 13 Feb 17 nicklas 290     else
4353 13 Feb 17 nicklas 291     {
4353 13 Feb 17 nicklas 292       ItemSubtype s = result.get(0);
4353 13 Feb 17 nicklas 293       json.put("id", s.getId());
4353 13 Feb 17 nicklas 294       json.put("status", "ok"); // For now -- more checks below
4353 13 Feb 17 nicklas 295       
4353 13 Feb 17 nicklas 296       if (subtype.getPushAnnotations() != s.getPushAnnotations())
4353 13 Feb 17 nicklas 297       {
4360 15 Feb 17 nicklas 298         if (createIfMissing)
4360 15 Feb 17 nicklas 299         {
4360 15 Feb 17 nicklas 300           s.setPushAnnotations(subtype.getPushAnnotations());
4360 15 Feb 17 nicklas 301           jsonMessages.add("Fixed");
4360 15 Feb 17 nicklas 302         }
4360 15 Feb 17 nicklas 303         else
4360 15 Feb 17 nicklas 304         {
4360 15 Feb 17 nicklas 305           json.put("status", "incomplete");
4360 15 Feb 17 nicklas 306           jsonMessages.add("Should have 'Push annotations to parent'="+subtype.getPushAnnotations());
4360 15 Feb 17 nicklas 307         }
4353 13 Feb 17 nicklas 308       }
4353 13 Feb 17 nicklas 309       
4353 13 Feb 17 nicklas 310       if (relatedTo != null)
4353 13 Feb 17 nicklas 311       {
4353 13 Feb 17 nicklas 312         for (Subtype related : relatedTo)
4353 13 Feb 17 nicklas 313         {
4353 13 Feb 17 nicklas 314           ItemSubtype r = s.getRelatedSubtype(related.getMainType());
4353 13 Feb 17 nicklas 315           if (r == null)
4353 13 Feb 17 nicklas 316           {
4353 13 Feb 17 nicklas 317             r = related.get(dc);
4353 13 Feb 17 nicklas 318             if (createIfMissing && r != null)
4353 13 Feb 17 nicklas 319             {
4353 13 Feb 17 nicklas 320               s.setRelatedSubtype(r);
4353 13 Feb 17 nicklas 321               jsonMessages.add("Fixed");
4353 13 Feb 17 nicklas 322             }
4353 13 Feb 17 nicklas 323             else
4353 13 Feb 17 nicklas 324             {
4353 13 Feb 17 nicklas 325               json.put("status", "incomplete");
4353 13 Feb 17 nicklas 326               jsonMessages.add("Should be related to '" + related.getName() + "' [" + related.getMainType().name() + "]");
4353 13 Feb 17 nicklas 327             }
4353 13 Feb 17 nicklas 328           }
4353 13 Feb 17 nicklas 329           else if (!r.getName().equals(related.getName()))
4353 13 Feb 17 nicklas 330           {
4353 13 Feb 17 nicklas 331             if (createIfMissing)
4353 13 Feb 17 nicklas 332             {
4353 13 Feb 17 nicklas 333               s.setRelatedSubtype(related.get(dc));
4353 13 Feb 17 nicklas 334               jsonMessages.add("Fixed");
4353 13 Feb 17 nicklas 335             }
4353 13 Feb 17 nicklas 336             else
4353 13 Feb 17 nicklas 337             {
4353 13 Feb 17 nicklas 338               json.put("status", "incomplete");
4353 13 Feb 17 nicklas 339               jsonMessages.add("Should be related to: '" + 
4353 13 Feb 17 nicklas 340                   related.getName() + "' not '" + r.getName() + "'");
4353 13 Feb 17 nicklas 341             }
4353 13 Feb 17 nicklas 342           }
4353 13 Feb 17 nicklas 343         }
4353 13 Feb 17 nicklas 344       }
4353 13 Feb 17 nicklas 345       
4353 13 Feb 17 nicklas 346     }
4353 13 Feb 17 nicklas 347     if (jsonMessages.size() == 0) jsonMessages.add("Ok");
4353 13 Feb 17 nicklas 348     json.put("messages", jsonMessages);
4353 13 Feb 17 nicklas 349     return json;
4353 13 Feb 17 nicklas 350   
4353 13 Feb 17 nicklas 351   }
4353 13 Feb 17 nicklas 352
5177 05 Dec 18 nicklas 353   /**
5177 05 Dec 18 nicklas 354     Create an annotation type category with the given options. The category
5177 05 Dec 18 nicklas 355     is created in a separate transaction.
5177 05 Dec 18 nicklas 356     @since 1.4
5177 05 Dec 18 nicklas 357   */
5177 05 Dec 18 nicklas 358   public AnnotationTypeCategory createAnnotationTypeCategory(SessionControl sc, String name)
5177 05 Dec 18 nicklas 359   {
5177 05 Dec 18 nicklas 360     AnnotationTypeCategory cat = null;
6779 17 Jun 22 nicklas 361     DbControl dc = sc.newDbControl("Relax: install");
5177 05 Dec 18 nicklas 362     try
5177 05 Dec 18 nicklas 363     {
5177 05 Dec 18 nicklas 364       cat = AnnotationTypeCategory.getNew(dc);
5177 05 Dec 18 nicklas 365       cat.setName(name);
5177 05 Dec 18 nicklas 366       dc.saveItem(cat);
5177 05 Dec 18 nicklas 367       dc.commit();
5177 05 Dec 18 nicklas 368     }
5177 05 Dec 18 nicklas 369     finally
5177 05 Dec 18 nicklas 370     {
5177 05 Dec 18 nicklas 371       if (dc != null) dc.close();
5177 05 Dec 18 nicklas 372     }
5177 05 Dec 18 nicklas 373     return cat;
5177 05 Dec 18 nicklas 374   }
5176 05 Dec 18 nicklas 375   
5177 05 Dec 18 nicklas 376   public JSONObject checkAnnotationTypeCategory(DbControl dc, Subtype subtype, 
5177 05 Dec 18 nicklas 377     boolean createIfMissing, Annotationtype... annotationTypes)
5177 05 Dec 18 nicklas 378   {
5177 05 Dec 18 nicklas 379     return checkAnnotationTypeCategory(dc, subtype.getName(), createIfMissing, annotationTypes);
5177 05 Dec 18 nicklas 380   }
5177 05 Dec 18 nicklas 381   
4406 20 Mar 17 nicklas 382   /**
5177 05 Dec 18 nicklas 383     List all annotation types with the given name.
5177 05 Dec 18 nicklas 384     @since 1.4
5177 05 Dec 18 nicklas 385   */
5177 05 Dec 18 nicklas 386   public List<AnnotationTypeCategory> listAnnotationTypeCategories(DbControl dc, String name)
5177 05 Dec 18 nicklas 387   {
5177 05 Dec 18 nicklas 388     ItemQuery<AnnotationTypeCategory> query = AnnotationTypeCategory.getQuery();
5177 05 Dec 18 nicklas 389     query.restrict(Restrictions.eq(Hql.property("name"), Expressions.parameter("name", name, Type.STRING)));
5177 05 Dec 18 nicklas 390     query.include(Include.ALL);
5177 05 Dec 18 nicklas 391     return query.list(dc);
5177 05 Dec 18 nicklas 392   }
5177 05 Dec 18 nicklas 393   
5177 05 Dec 18 nicklas 394   /**
5177 05 Dec 18 nicklas 395     Check for an existing annotation type category.
5177 05 Dec 18 nicklas 396     A JSONObject is returned with the result. The following 
5177 05 Dec 18 nicklas 397     keys are used:
5177 05 Dec 18 nicklas 398     <ul>
5177 05 Dec 18 nicklas 399     <li>itemType: ANNOTATIONTYPECATEGORY
5177 05 Dec 18 nicklas 400     <li>name: The name of the category
5177 05 Dec 18 nicklas 401     <li>id: The id of the category if it exists
5177 05 Dec 18 nicklas 402     <li>status: ok, error, or missing
5177 05 Dec 18 nicklas 403     <li>message: A descriptive message in case of an error
5177 05 Dec 18 nicklas 404     </ul>
5177 05 Dec 18 nicklas 405     @since 1.4
5177 05 Dec 18 nicklas 406   */
5177 05 Dec 18 nicklas 407   public JSONObject checkAnnotationTypeCategory(DbControl dc, String name, 
5177 05 Dec 18 nicklas 408     boolean createIfMissing, Annotationtype... annotationTypes)
5177 05 Dec 18 nicklas 409   {
5177 05 Dec 18 nicklas 410   
5177 05 Dec 18 nicklas 411     JSONObject json = new JSONObject();
5177 05 Dec 18 nicklas 412     JSONArray jsonMessages = new JSONArray();
5177 05 Dec 18 nicklas 413     json.put("itemType", Item.ANNOTATIONTYPECATEGORY.name());
5177 05 Dec 18 nicklas 414     json.put("name", name);
5177 05 Dec 18 nicklas 415       
5177 05 Dec 18 nicklas 416     List<AnnotationTypeCategory> result = listAnnotationTypeCategories(dc, name);
5177 05 Dec 18 nicklas 417     if (result.size() == 0)
5177 05 Dec 18 nicklas 418     {
5177 05 Dec 18 nicklas 419       if (createIfMissing)
5177 05 Dec 18 nicklas 420       {
5177 05 Dec 18 nicklas 421         AnnotationTypeCategory cat = createAnnotationTypeCategory(dc.getSessionControl(), name);
5177 05 Dec 18 nicklas 422         // Add the category to annotation types in the original transaction
5177 05 Dec 18 nicklas 423         if (annotationTypes != null)
5177 05 Dec 18 nicklas 424         {
5177 05 Dec 18 nicklas 425           for (Annotationtype annotationType : annotationTypes)
5177 05 Dec 18 nicklas 426           {
5177 05 Dec 18 nicklas 427             AnnotationType at = annotationType.load(dc);
5177 05 Dec 18 nicklas 428             at.addCategory(cat);
5177 05 Dec 18 nicklas 429           }
5177 05 Dec 18 nicklas 430         }
5177 05 Dec 18 nicklas 431   
5177 05 Dec 18 nicklas 432         json.put("id", cat.getId());
5177 05 Dec 18 nicklas 433         json.put("status", "ok");
5177 05 Dec 18 nicklas 434         jsonMessages.add("Created");
5177 05 Dec 18 nicklas 435       }
5177 05 Dec 18 nicklas 436       else
5177 05 Dec 18 nicklas 437       {
5177 05 Dec 18 nicklas 438         json.put("status", "missing");
5177 05 Dec 18 nicklas 439         jsonMessages.add("Not found");
5177 05 Dec 18 nicklas 440       }
5177 05 Dec 18 nicklas 441     }
5177 05 Dec 18 nicklas 442     else if (result.size() > 1)
5177 05 Dec 18 nicklas 443     {
5177 05 Dec 18 nicklas 444       json.put("status", "error");
5177 05 Dec 18 nicklas 445       jsonMessages.add("Found > 1 annotation type category");
5177 05 Dec 18 nicklas 446     }
5177 05 Dec 18 nicklas 447     else
5177 05 Dec 18 nicklas 448     {
5177 05 Dec 18 nicklas 449       AnnotationTypeCategory cat = result.get(0);
5177 05 Dec 18 nicklas 450       json.put("id", cat.getId());
5177 05 Dec 18 nicklas 451       json.put("status", "ok"); // For now -- more checks below
5177 05 Dec 18 nicklas 452       
5177 05 Dec 18 nicklas 453       if (annotationTypes != null)
5177 05 Dec 18 nicklas 454       {
5177 05 Dec 18 nicklas 455         for (Annotationtype annotationType : annotationTypes)
5177 05 Dec 18 nicklas 456         {
5177 05 Dec 18 nicklas 457           AnnotationType at = annotationType.get(dc);
5177 05 Dec 18 nicklas 458           if (at != null && !at.isMember(cat))
5177 05 Dec 18 nicklas 459           {
5177 05 Dec 18 nicklas 460             if (createIfMissing)
5177 05 Dec 18 nicklas 461             {
5177 05 Dec 18 nicklas 462               at.addCategory(cat);
5177 05 Dec 18 nicklas 463               if (jsonMessages.size() == 0) jsonMessages.add("Fixed");
5177 05 Dec 18 nicklas 464             }
5177 05 Dec 18 nicklas 465             else
5177 05 Dec 18 nicklas 466             {
5177 05 Dec 18 nicklas 467               json.put("status", "incomplete");
5177 05 Dec 18 nicklas 468               jsonMessages.add("Not linked with: " + annotationType.getName());
5177 05 Dec 18 nicklas 469             }
5177 05 Dec 18 nicklas 470           }
5177 05 Dec 18 nicklas 471         }
5177 05 Dec 18 nicklas 472       }
5177 05 Dec 18 nicklas 473     }
5177 05 Dec 18 nicklas 474     if (jsonMessages.size() == 0) jsonMessages.add("Ok");
5177 05 Dec 18 nicklas 475     json.put("messages", jsonMessages);
5177 05 Dec 18 nicklas 476     return json;
5177 05 Dec 18 nicklas 477   
5177 05 Dec 18 nicklas 478   }
5177 05 Dec 18 nicklas 479   /**
5176 05 Dec 18 nicklas 480     Creates an annotation type with the given options. The annotation
5176 05 Dec 18 nicklas 481     type is created in a separate transaction. The annotation can be enabled for 
5176 05 Dec 18 nicklas 482     one or more item-types.
5176 05 Dec 18 nicklas 483     
5176 05 Dec 18 nicklas 484     @since 1.4
5176 05 Dec 18 nicklas 485    */
5176 05 Dec 18 nicklas 486   public AnnotationType createAnnotationType(SessionControl sc, Annotationtype annotationType, 
5176 05 Dec 18 nicklas 487     ValueOptions valueOptions, PermissionOptions... permissions)
5176 05 Dec 18 nicklas 488   {
5176 05 Dec 18 nicklas 489     AnnotationType at = null;
6779 17 Jun 22 nicklas 490     DbControl dc = sc.newDbControl("Relax: install");
5176 05 Dec 18 nicklas 491     try
5176 05 Dec 18 nicklas 492     {
5176 05 Dec 18 nicklas 493       at = AnnotationType.getNew(dc, annotationType.getValueType());
5176 05 Dec 18 nicklas 494       at.setName(annotationType.getName());
5176 05 Dec 18 nicklas 495       for (Item it : annotationType.getMainType())
5176 05 Dec 18 nicklas 496       {
5176 05 Dec 18 nicklas 497         at.enableForItem(it);
5176 05 Dec 18 nicklas 498       }
5176 05 Dec 18 nicklas 499       at.setMultiplicity(1);
5176 05 Dec 18 nicklas 500       if (valueOptions != null)
5176 05 Dec 18 nicklas 501       {
5176 05 Dec 18 nicklas 502         if (valueOptions.isEnumeration())
5176 05 Dec 18 nicklas 503         {
5176 05 Dec 18 nicklas 504           at.setEnumeration(true);
5176 05 Dec 18 nicklas 505           at.setDisplayAsList(false);
5176 05 Dec 18 nicklas 506           at.setValues(valueOptions.getList());
5176 05 Dec 18 nicklas 507         }
5176 05 Dec 18 nicklas 508       }
5176 05 Dec 18 nicklas 509       if (permissions != null) 
5176 05 Dec 18 nicklas 510       {
5176 05 Dec 18 nicklas 511         for (PermissionOptions p : permissions)
5176 05 Dec 18 nicklas 512         {
5176 05 Dec 18 nicklas 513           p.applyPermissions(at);
5176 05 Dec 18 nicklas 514         }
5176 05 Dec 18 nicklas 515       }
5176 05 Dec 18 nicklas 516       dc.saveItem(at);
5176 05 Dec 18 nicklas 517       dc.commit();
5176 05 Dec 18 nicklas 518     }
5176 05 Dec 18 nicklas 519     finally
5176 05 Dec 18 nicklas 520     {
5176 05 Dec 18 nicklas 521       if (dc != null) dc.close();
5176 05 Dec 18 nicklas 522     }
5176 05 Dec 18 nicklas 523     return at;
5176 05 Dec 18 nicklas 524   }
5176 05 Dec 18 nicklas 525   
5176 05 Dec 18 nicklas 526   /**
5176 05 Dec 18 nicklas 527     Check for an existing annotation type with the given options. A JSONObject is returned
5176 05 Dec 18 nicklas 528     with the result. The following keys are used:
5176 05 Dec 18 nicklas 529     <ul>
5176 05 Dec 18 nicklas 530     <li>itemType: ANNOTATIONTYPE
5176 05 Dec 18 nicklas 531     <li>name: The name of the annotation type
5176 05 Dec 18 nicklas 532     <li>id: The id of the annotation type if it exists
5176 05 Dec 18 nicklas 533     <li>status: ok, error, or missing
5176 05 Dec 18 nicklas 534     <li>message: A descriptive message in case of an error
5176 05 Dec 18 nicklas 535     </ul>
5176 05 Dec 18 nicklas 536     
5176 05 Dec 18 nicklas 537     @since 2.5
5176 05 Dec 18 nicklas 538   */
5176 05 Dec 18 nicklas 539   public JSONObject checkAnnotationType(DbControl dc, Annotationtype annotationType, 
5176 05 Dec 18 nicklas 540       ValueOptions valueOptions, boolean createIfMissing, PermissionOptions... permissions)
5176 05 Dec 18 nicklas 541   {
5176 05 Dec 18 nicklas 542     JSONObject json = new JSONObject();
5176 05 Dec 18 nicklas 543     JSONArray jsonMessages = new JSONArray();
5176 05 Dec 18 nicklas 544     json.put("itemType", Item.ANNOTATIONTYPE.name());
5176 05 Dec 18 nicklas 545     json.put("name", annotationType.getName());
5176 05 Dec 18 nicklas 546     
5176 05 Dec 18 nicklas 547     List<AnnotationType> result = annotationType.list(dc);
5176 05 Dec 18 nicklas 548     if (result.size() == 0)
5176 05 Dec 18 nicklas 549     {
5176 05 Dec 18 nicklas 550       if (createIfMissing)
5176 05 Dec 18 nicklas 551       {
5176 05 Dec 18 nicklas 552         AnnotationType at = createAnnotationType(dc.getSessionControl(), annotationType, valueOptions, permissions);
5176 05 Dec 18 nicklas 553         json.put("id", at.getId());
5176 05 Dec 18 nicklas 554         json.put("status", "ok");
5176 05 Dec 18 nicklas 555         jsonMessages.add("Created");
5176 05 Dec 18 nicklas 556       }
5176 05 Dec 18 nicklas 557       else
5176 05 Dec 18 nicklas 558       {
5176 05 Dec 18 nicklas 559         json.put("status", "missing");
5176 05 Dec 18 nicklas 560         jsonMessages.add("Not found");
5176 05 Dec 18 nicklas 561       }
5176 05 Dec 18 nicklas 562     }
5176 05 Dec 18 nicklas 563     else if (result.size() > 1)
5176 05 Dec 18 nicklas 564     {
5176 05 Dec 18 nicklas 565       json.put("status", "error");
5176 05 Dec 18 nicklas 566       jsonMessages.add("Found > 1 annotation type");
5176 05 Dec 18 nicklas 567     }
5176 05 Dec 18 nicklas 568     else
5176 05 Dec 18 nicklas 569     {
5176 05 Dec 18 nicklas 570       AnnotationType at = result.get(0);
5176 05 Dec 18 nicklas 571       json.put("id", at.getId());
5176 05 Dec 18 nicklas 572       json.put("status", "ok");// For now -- more checks below
5176 05 Dec 18 nicklas 573       if (permissions != null)
5176 05 Dec 18 nicklas 574       {
5176 05 Dec 18 nicklas 575         String permissionCheck = null;
5176 05 Dec 18 nicklas 576         for (PermissionOptions p : permissions)
5176 05 Dec 18 nicklas 577         {
5176 05 Dec 18 nicklas 578           if (!p.checkPermissions(at))
5176 05 Dec 18 nicklas 579           {
5176 05 Dec 18 nicklas 580             permissionCheck = p.getMessage();
5176 05 Dec 18 nicklas 581             break;
5176 05 Dec 18 nicklas 582           }
5176 05 Dec 18 nicklas 583         }
5176 05 Dec 18 nicklas 584         
5176 05 Dec 18 nicklas 585         if (permissionCheck != null)
5176 05 Dec 18 nicklas 586         {
5176 05 Dec 18 nicklas 587           if (createIfMissing)
5176 05 Dec 18 nicklas 588           {
5176 05 Dec 18 nicklas 589             for (PermissionOptions p : permissions)
5176 05 Dec 18 nicklas 590             {
5176 05 Dec 18 nicklas 591               p.applyPermissions(at);
5176 05 Dec 18 nicklas 592             }
5176 05 Dec 18 nicklas 593             if (jsonMessages.size() == 0) jsonMessages.add("Fixed");
5176 05 Dec 18 nicklas 594           }
5176 05 Dec 18 nicklas 595           else
5176 05 Dec 18 nicklas 596           {
5176 05 Dec 18 nicklas 597             json.put("status", "incomplete");
5176 05 Dec 18 nicklas 598             jsonMessages.add(permissionCheck);
5176 05 Dec 18 nicklas 599           }
5176 05 Dec 18 nicklas 600         }
5176 05 Dec 18 nicklas 601       }
5176 05 Dec 18 nicklas 602       boolean allTypesOk = true;
5176 05 Dec 18 nicklas 603       boolean fixedTypes = false;
5176 05 Dec 18 nicklas 604       for (Item it : annotationType.getMainType())
5176 05 Dec 18 nicklas 605       {
5176 05 Dec 18 nicklas 606         if (!at.isEnabledForItem(it))
5176 05 Dec 18 nicklas 607         {
5176 05 Dec 18 nicklas 608           allTypesOk = false;
5176 05 Dec 18 nicklas 609           if (createIfMissing)
5176 05 Dec 18 nicklas 610           {
5176 05 Dec 18 nicklas 611             at.enableForItem(it);
5176 05 Dec 18 nicklas 612             fixedTypes = true;
5176 05 Dec 18 nicklas 613           }
5176 05 Dec 18 nicklas 614           else
5176 05 Dec 18 nicklas 615           {
5176 05 Dec 18 nicklas 616             json.put("status", "incomplete");
5176 05 Dec 18 nicklas 617             jsonMessages.add("Not enabled for " + it.name());
5176 05 Dec 18 nicklas 618           }
5176 05 Dec 18 nicklas 619         }
5176 05 Dec 18 nicklas 620       }
5176 05 Dec 18 nicklas 621       if (fixedTypes && jsonMessages.size() == 0) jsonMessages.add("Fixed");
5176 05 Dec 18 nicklas 622       if (at.getValueType() != annotationType.getValueType())
5176 05 Dec 18 nicklas 623       {
5176 05 Dec 18 nicklas 624         json.put("status", "error");
5176 05 Dec 18 nicklas 625         jsonMessages.add("Is not a " + annotationType.getValueType().name() + " type");
5176 05 Dec 18 nicklas 626       }
5176 05 Dec 18 nicklas 627       if (at.getMultiplicity() != 1)
5176 05 Dec 18 nicklas 628       {
5176 05 Dec 18 nicklas 629         json.put("status", "error");
5176 05 Dec 18 nicklas 630         jsonMessages.add("Should have multiplicity=1");
5176 05 Dec 18 nicklas 631       }
5176 05 Dec 18 nicklas 632       if (at.isEnumeration() && (valueOptions == null || !valueOptions.isEnumeration()))
5176 05 Dec 18 nicklas 633       {
5176 05 Dec 18 nicklas 634         json.put("status", "error");
5176 05 Dec 18 nicklas 635         jsonMessages.add("Should not be an enumeration");
5176 05 Dec 18 nicklas 636       }
5176 05 Dec 18 nicklas 637       if (valueOptions != null)
5176 05 Dec 18 nicklas 638       {
5176 05 Dec 18 nicklas 639         if (valueOptions.isEnumeration())
5176 05 Dec 18 nicklas 640         {
5176 05 Dec 18 nicklas 641           if (!at.isEnumeration())
5176 05 Dec 18 nicklas 642           {
5176 05 Dec 18 nicklas 643             json.put("status", "error");
5176 05 Dec 18 nicklas 644             jsonMessages.add("Is not enumeration of: " + valueOptions.getList());
5176 05 Dec 18 nicklas 645           }
5176 05 Dec 18 nicklas 646           else if (!at.getValues().containsAll(valueOptions.getList()))
5176 05 Dec 18 nicklas 647           {
5176 05 Dec 18 nicklas 648             if (createIfMissing)
5176 05 Dec 18 nicklas 649             {
5176 05 Dec 18 nicklas 650               valueOptions.applyEnumeration(at);
5176 05 Dec 18 nicklas 651               if (jsonMessages.size() == 0) jsonMessages.add("Fixed");
5176 05 Dec 18 nicklas 652             }
5176 05 Dec 18 nicklas 653             else
5176 05 Dec 18 nicklas 654             {
5176 05 Dec 18 nicklas 655               json.put("status", "incomplete");
5176 05 Dec 18 nicklas 656               jsonMessages.add("Doesn't have all options: " + valueOptions.getList() + "!=" + at.getValues());
5176 05 Dec 18 nicklas 657             }
5176 05 Dec 18 nicklas 658           }
5176 05 Dec 18 nicklas 659         }
5176 05 Dec 18 nicklas 660       }
5176 05 Dec 18 nicklas 661     }
5176 05 Dec 18 nicklas 662     if (jsonMessages.size() == 0) jsonMessages.add("Ok");
5176 05 Dec 18 nicklas 663     json.put("messages", jsonMessages);
5176 05 Dec 18 nicklas 664     return json;
5176 05 Dec 18 nicklas 665   }
5176 05 Dec 18 nicklas 666
5176 05 Dec 18 nicklas 667   
5176 05 Dec 18 nicklas 668   /**
4406 20 Mar 17 nicklas 669     Create a file server with the given options. The file server is created in
4406 20 Mar 17 nicklas 670     a separate transaction.
4406 20 Mar 17 nicklas 671     @since 2.16
4406 20 Mar 17 nicklas 672   */
4406 20 Mar 17 nicklas 673   public FileServer createFileServer(SessionControl sc, Fileserver def, PermissionOptions permissions)
4406 20 Mar 17 nicklas 674   {
4406 20 Mar 17 nicklas 675     FileServer fs = null;
6779 17 Jun 22 nicklas 676     DbControl dc = sc.newDbControl("Relax: install");
4406 20 Mar 17 nicklas 677     try
4406 20 Mar 17 nicklas 678     {
4406 20 Mar 17 nicklas 679       fs = FileServer.getNew(dc);
4406 20 Mar 17 nicklas 680       fs.setName(def.getName());
4406 20 Mar 17 nicklas 681       fs.setConnectionManagerFactoryId(def.getConnectionManagerId());
4406 20 Mar 17 nicklas 682       fs.setDescription(def.getDescription());
4406 20 Mar 17 nicklas 683       if (permissions != null) permissions.applyPermissions(fs);
4406 20 Mar 17 nicklas 684       
4406 20 Mar 17 nicklas 685       dc.saveItem(fs);
4406 20 Mar 17 nicklas 686       dc.commit();
4406 20 Mar 17 nicklas 687     }
4406 20 Mar 17 nicklas 688     finally
4406 20 Mar 17 nicklas 689     {
4406 20 Mar 17 nicklas 690       if (dc != null) dc.close();
4406 20 Mar 17 nicklas 691     }
4406 20 Mar 17 nicklas 692     return fs;
4406 20 Mar 17 nicklas 693   }
4406 20 Mar 17 nicklas 694   
4406 20 Mar 17 nicklas 695   
4406 20 Mar 17 nicklas 696   /**
4406 20 Mar 17 nicklas 697     Check for an existing file server with the given options.
4406 20 Mar 17 nicklas 698     A JSONObject is returned with the result. The following 
4406 20 Mar 17 nicklas 699     keys are used:
4406 20 Mar 17 nicklas 700     <ul>
4406 20 Mar 17 nicklas 701     <li>itemType: FILESERVER
4406 20 Mar 17 nicklas 702     <li>name: The name of the fileserver
4406 20 Mar 17 nicklas 703     <li>id: The id of the fileserver if it exists
4406 20 Mar 17 nicklas 704     <li>status: ok, error, or missing
4406 20 Mar 17 nicklas 705     <li>message: A descriptive message in case of an error
4406 20 Mar 17 nicklas 706     </ul>
4406 20 Mar 17 nicklas 707     @since 2.16
4406 20 Mar 17 nicklas 708   */
4406 20 Mar 17 nicklas 709   public JSONObject checkFileServer(DbControl dc, Fileserver fileServer, 
4406 20 Mar 17 nicklas 710     boolean createIfMissing, PermissionOptions permissions)
4406 20 Mar 17 nicklas 711   {
4406 20 Mar 17 nicklas 712   
4406 20 Mar 17 nicklas 713     JSONObject json = new JSONObject();
4406 20 Mar 17 nicklas 714     JSONArray jsonMessages = new JSONArray();
4406 20 Mar 17 nicklas 715     json.put("itemType", Item.FILESERVER.name());
4406 20 Mar 17 nicklas 716     json.put("name", fileServer.getName());
4406 20 Mar 17 nicklas 717     
4406 20 Mar 17 nicklas 718     FileServer fs = null;
4406 20 Mar 17 nicklas 719     List<FileServer> result = fileServer.list(dc);
4406 20 Mar 17 nicklas 720     if (result.size() == 0)
4406 20 Mar 17 nicklas 721     {
4406 20 Mar 17 nicklas 722       if (createIfMissing)
4406 20 Mar 17 nicklas 723       {
4406 20 Mar 17 nicklas 724         fs = createFileServer(dc.getSessionControl(), fileServer, permissions);
4406 20 Mar 17 nicklas 725         fs = FileServer.getById(dc, fs.getId());
4406 20 Mar 17 nicklas 726         json.put("id", fs.getId());
4406 20 Mar 17 nicklas 727         // Not ok yet, need manual configuration which is checked below
4406 20 Mar 17 nicklas 728       }
4406 20 Mar 17 nicklas 729       else
4406 20 Mar 17 nicklas 730       {
4406 20 Mar 17 nicklas 731         json.put("status", "missing");
4406 20 Mar 17 nicklas 732         jsonMessages.add("Not found");
4406 20 Mar 17 nicklas 733       }
4406 20 Mar 17 nicklas 734     }
4406 20 Mar 17 nicklas 735     else if (result.size() > 1)
4406 20 Mar 17 nicklas 736     {
4406 20 Mar 17 nicklas 737       json.put("status", "error");
4406 20 Mar 17 nicklas 738       jsonMessages.add("Found > 1 file server");
4406 20 Mar 17 nicklas 739     }
4406 20 Mar 17 nicklas 740     else
4406 20 Mar 17 nicklas 741     {
4406 20 Mar 17 nicklas 742       fs = result.get(0);
4406 20 Mar 17 nicklas 743     }
4406 20 Mar 17 nicklas 744     
4406 20 Mar 17 nicklas 745     if (fs != null)
4406 20 Mar 17 nicklas 746     {
4406 20 Mar 17 nicklas 747       json.put("id", fs.getId());
4406 20 Mar 17 nicklas 748       json.put("status", "ok"); // For now -- more checks below
4406 20 Mar 17 nicklas 749       
4406 20 Mar 17 nicklas 750       if (permissions != null && !permissions.checkPermissions(fs))
4406 20 Mar 17 nicklas 751       {
4406 20 Mar 17 nicklas 752         if (createIfMissing)
4406 20 Mar 17 nicklas 753         {
4406 20 Mar 17 nicklas 754           permissions.applyPermissions(fs);
4406 20 Mar 17 nicklas 755           if (jsonMessages.size() == 0) jsonMessages.add("Fixed");
4406 20 Mar 17 nicklas 756         }
4406 20 Mar 17 nicklas 757         else
4406 20 Mar 17 nicklas 758         {
4406 20 Mar 17 nicklas 759           json.put("status", "incomplete");
4406 20 Mar 17 nicklas 760           jsonMessages.add(permissions.getMessage());
4406 20 Mar 17 nicklas 761         }
4406 20 Mar 17 nicklas 762       }
4406 20 Mar 17 nicklas 763       
4406 20 Mar 17 nicklas 764       if (!fileServer.getConnectionManagerId().equals(fs.getConnectionManagerFactoryId()))
4406 20 Mar 17 nicklas 765       {
4406 20 Mar 17 nicklas 766         if (createIfMissing)
4406 20 Mar 17 nicklas 767         {
4406 20 Mar 17 nicklas 768           fs.setConnectionManagerFactoryId(fileServer.getConnectionManagerId());
4406 20 Mar 17 nicklas 769         }
4406 20 Mar 17 nicklas 770         else
4406 20 Mar 17 nicklas 771         {
4406 20 Mar 17 nicklas 772           json.put("status", "incomplete");
4406 20 Mar 17 nicklas 773           jsonMessages.add("Should use SFTP connection manager");
4406 20 Mar 17 nicklas 774         }
4406 20 Mar 17 nicklas 775       }
4406 20 Mar 17 nicklas 776       
4406 20 Mar 17 nicklas 777       if (fs.getHost() == null)
4406 20 Mar 17 nicklas 778       {
4406 20 Mar 17 nicklas 779         json.put("status", "warning");
4406 20 Mar 17 nicklas 780         jsonMessages.add("No host name configured");
4406 20 Mar 17 nicklas 781       }
4406 20 Mar 17 nicklas 782       
4406 20 Mar 17 nicklas 783       if (fs.getUsername() == null)
4406 20 Mar 17 nicklas 784       {
4406 20 Mar 17 nicklas 785         json.put("status", "warning");
4406 20 Mar 17 nicklas 786         jsonMessages.add("No user configured");
4406 20 Mar 17 nicklas 787       }
4406 20 Mar 17 nicklas 788       
5578 16 Aug 19 nicklas 789       if (!fs.hasPassword() && !fs.hasSshPrivateKey())
4406 20 Mar 17 nicklas 790       {
4406 20 Mar 17 nicklas 791         json.put("status", "warning");
5578 16 Aug 19 nicklas 792         jsonMessages.add("No password or private-key configured");
4406 20 Mar 17 nicklas 793       }
4406 20 Mar 17 nicklas 794   
4406 20 Mar 17 nicklas 795       if (fs.getRootPath() == null)
4406 20 Mar 17 nicklas 796       {
4406 20 Mar 17 nicklas 797         json.put("status", "warning");
4406 20 Mar 17 nicklas 798         jsonMessages.add("No root path configured");
4406 20 Mar 17 nicklas 799       }
4406 20 Mar 17 nicklas 800       
4406 20 Mar 17 nicklas 801       if (fs.getSshFingerprint() == null)
4406 20 Mar 17 nicklas 802       {
4406 20 Mar 17 nicklas 803         json.put("status", "warning");
4406 20 Mar 17 nicklas 804         jsonMessages.add("No SSH fingerprint configured");
4406 20 Mar 17 nicklas 805       }
4406 20 Mar 17 nicklas 806       
4406 20 Mar 17 nicklas 807       if (json.get("status").equals("ok"))
4406 20 Mar 17 nicklas 808       {
4406 20 Mar 17 nicklas 809         ConnectionManagerFactory cmf = ConnectionManagerUtil.getFactory(fs.getConnectionManagerFactoryId());
4406 20 Mar 17 nicklas 810         if (cmf == null)
4406 20 Mar 17 nicklas 811         {
4406 20 Mar 17 nicklas 812           json.put("status", "warning");
4406 20 Mar 17 nicklas 813           jsonMessages.add("SFTP connection manager is not installed");
4406 20 Mar 17 nicklas 814         }
4406 20 Mar 17 nicklas 815         else
4406 20 Mar 17 nicklas 816         {
4406 20 Mar 17 nicklas 817           ConnectionParameters cp = new ConnectionParameters();
4406 20 Mar 17 nicklas 818           cp.setHost(fs.getHost());
4406 20 Mar 17 nicklas 819           cp.setUsername(fs.getUsername());
4406 20 Mar 17 nicklas 820           cp.setPassword(fs.getPassword());
4406 20 Mar 17 nicklas 821           cp.setRootPath(fs.getRootPath());
4406 20 Mar 17 nicklas 822           cp.setSshFingerprint(fs.getSshFingerprint());
5578 16 Aug 19 nicklas 823           byte[] privateKey = fs.getSshPrivateKey();
5578 16 Aug 19 nicklas 824           if (privateKey != null && privateKey.length > 0)
5578 16 Aug 19 nicklas 825           {
5578 16 Aug 19 nicklas 826             cp.setSshPrivateKey(privateKey);
5578 16 Aug 19 nicklas 827             cp.setSshPrivateKeyPassword(fs.getSshPrivateKeyPassword());
5578 16 Aug 19 nicklas 828             cp.setSshPrivateKeyFormat(fs.getSshPrivateKeyFormat());
5578 16 Aug 19 nicklas 829           }
4406 20 Mar 17 nicklas 830           URI uri = cp.changeHost(URI.create("sftp://" + fs.getHost() + "/"));
4406 20 Mar 17 nicklas 831           ConnectionManager cm = cmf.createConnectionManager(uri, cp);
4406 20 Mar 17 nicklas 832           try
4406 20 Mar 17 nicklas 833           {
4406 20 Mar 17 nicklas 834             UriMetadata meta = cm.getMetadata();
4406 20 Mar 17 nicklas 835           }
4406 20 Mar 17 nicklas 836           catch (IOException ex)
4406 20 Mar 17 nicklas 837           {
4406 20 Mar 17 nicklas 838             json.put("status", "warning");
5578 16 Aug 19 nicklas 839             json.put("stacktrace", ThrowableUtil.stackTraceToString(ex));
4406 20 Mar 17 nicklas 840             jsonMessages.add(uri + ": " + ex.getMessage());
4406 20 Mar 17 nicklas 841           }
4406 20 Mar 17 nicklas 842         }
4406 20 Mar 17 nicklas 843       }
4406 20 Mar 17 nicklas 844     }
4406 20 Mar 17 nicklas 845     if (jsonMessages.size() == 0) jsonMessages.add("Ok");
4406 20 Mar 17 nicklas 846     json.put("messages", jsonMessages);
4406 20 Mar 17 nicklas 847     return json;
4406 20 Mar 17 nicklas 848   
4406 20 Mar 17 nicklas 849   }
4406 20 Mar 17 nicklas 850
4406 20 Mar 17 nicklas 851   
4406 20 Mar 17 nicklas 852   /**
4406 20 Mar 17 nicklas 853     Create a directory with the given options. The directory is created in
4406 20 Mar 17 nicklas 854     a separate transaction.
4406 20 Mar 17 nicklas 855     @since 4.0
4406 20 Mar 17 nicklas 856   */
4406 20 Mar 17 nicklas 857   public Directory createDirectory(SessionControl sc, Path path, PermissionOptions... permissions)
4406 20 Mar 17 nicklas 858   {
4406 20 Mar 17 nicklas 859     Directory d = null;
6779 17 Jun 22 nicklas 860     DbControl dc = sc.newDbControl("Relax: install");
4406 20 Mar 17 nicklas 861     try
4406 20 Mar 17 nicklas 862     {
4406 20 Mar 17 nicklas 863       d = Directory.getNew(dc, path);
4406 20 Mar 17 nicklas 864       if (permissions != null) 
4406 20 Mar 17 nicklas 865       {
4406 20 Mar 17 nicklas 866         for (PermissionOptions p : permissions)
4406 20 Mar 17 nicklas 867         {
4406 20 Mar 17 nicklas 868           p.applyPermissions(d);
4406 20 Mar 17 nicklas 869         }
4406 20 Mar 17 nicklas 870       }
4406 20 Mar 17 nicklas 871       dc.saveItem(d);
4406 20 Mar 17 nicklas 872       dc.commit();
4406 20 Mar 17 nicklas 873     }
4406 20 Mar 17 nicklas 874     finally
4406 20 Mar 17 nicklas 875     {
4406 20 Mar 17 nicklas 876       if (dc != null) dc.close();
4406 20 Mar 17 nicklas 877     }
4406 20 Mar 17 nicklas 878     return d;
4406 20 Mar 17 nicklas 879   }
4406 20 Mar 17 nicklas 880
4406 20 Mar 17 nicklas 881   /**
4406 20 Mar 17 nicklas 882     Check for an existing directory.
4406 20 Mar 17 nicklas 883     A JSONObject is returned with the result. The following 
4406 20 Mar 17 nicklas 884     keys are used:
4406 20 Mar 17 nicklas 885     <ul>
4406 20 Mar 17 nicklas 886     <li>itemType: DIRECTORY
4406 20 Mar 17 nicklas 887     <li>name: The full path of the directory
4406 20 Mar 17 nicklas 888     <li>id: The id of the directory if it exists
4406 20 Mar 17 nicklas 889     <li>status: ok, error, or missing
4406 20 Mar 17 nicklas 890     <li>message: A descriptive message in case of an error
4406 20 Mar 17 nicklas 891     </ul>
4406 20 Mar 17 nicklas 892   */
4406 20 Mar 17 nicklas 893   public JSONObject checkDirectory(DbControl dc, String name, 
4406 20 Mar 17 nicklas 894     boolean createIfMissing, PermissionOptions... permissions)
4406 20 Mar 17 nicklas 895   {
4406 20 Mar 17 nicklas 896   
4406 20 Mar 17 nicklas 897     JSONObject json = new JSONObject();
4406 20 Mar 17 nicklas 898     JSONArray jsonMessages = new JSONArray();
4406 20 Mar 17 nicklas 899     json.put("itemType", Item.DIRECTORY.name());
4406 20 Mar 17 nicklas 900     json.put("name", name);
4406 20 Mar 17 nicklas 901     
4406 20 Mar 17 nicklas 902     Directory d = null;
4406 20 Mar 17 nicklas 903     Path path = new Path(name, Path.Type.DIRECTORY);
4406 20 Mar 17 nicklas 904     try
4406 20 Mar 17 nicklas 905     {
4406 20 Mar 17 nicklas 906       d = Directory.getByPath(dc, path);
4406 20 Mar 17 nicklas 907     }
4406 20 Mar 17 nicklas 908     catch (RuntimeException ex)
4406 20 Mar 17 nicklas 909     {}
4406 20 Mar 17 nicklas 910     
4406 20 Mar 17 nicklas 911     if (d == null)
4406 20 Mar 17 nicklas 912     {
4406 20 Mar 17 nicklas 913       if (createIfMissing)
4406 20 Mar 17 nicklas 914       {
4406 20 Mar 17 nicklas 915         d = createDirectory(dc.getSessionControl(), path, permissions);
4406 20 Mar 17 nicklas 916         d = Directory.getById(dc, d.getId());
4406 20 Mar 17 nicklas 917         json.put("id", d.getId());
4406 20 Mar 17 nicklas 918       }
4406 20 Mar 17 nicklas 919       else
4406 20 Mar 17 nicklas 920       {
4406 20 Mar 17 nicklas 921         json.put("status", "missing");
4406 20 Mar 17 nicklas 922         jsonMessages.add("Not found");
4406 20 Mar 17 nicklas 923       }
4406 20 Mar 17 nicklas 924     }
4406 20 Mar 17 nicklas 925     
4406 20 Mar 17 nicklas 926     if (d != null)
4406 20 Mar 17 nicklas 927     {
4406 20 Mar 17 nicklas 928       json.put("id", d.getId());
4406 20 Mar 17 nicklas 929       json.put("status", "ok"); // For now -- more checks below
4406 20 Mar 17 nicklas 930       
4406 20 Mar 17 nicklas 931       if (permissions != null)
4406 20 Mar 17 nicklas 932       {
4406 20 Mar 17 nicklas 933         String permissionCheck = null;
4406 20 Mar 17 nicklas 934         for (PermissionOptions p : permissions)
4406 20 Mar 17 nicklas 935         {
4406 20 Mar 17 nicklas 936           if (!p.checkPermissions(d))
4406 20 Mar 17 nicklas 937           {
4406 20 Mar 17 nicklas 938             permissionCheck = p.getMessage();
4406 20 Mar 17 nicklas 939             break;
4406 20 Mar 17 nicklas 940           }
4406 20 Mar 17 nicklas 941         }
4406 20 Mar 17 nicklas 942         
4406 20 Mar 17 nicklas 943         if (permissionCheck != null)
4406 20 Mar 17 nicklas 944         {
4406 20 Mar 17 nicklas 945           if (createIfMissing)
4406 20 Mar 17 nicklas 946           {
4406 20 Mar 17 nicklas 947             for (PermissionOptions p : permissions)
4406 20 Mar 17 nicklas 948             {
4406 20 Mar 17 nicklas 949               p.applyPermissions(d);
4406 20 Mar 17 nicklas 950             }
4406 20 Mar 17 nicklas 951             if (jsonMessages.size() == 0) jsonMessages.add("Fixed");
4406 20 Mar 17 nicklas 952           }
4406 20 Mar 17 nicklas 953           else
4406 20 Mar 17 nicklas 954           {
4406 20 Mar 17 nicklas 955             json.put("status", "incomplete");
4406 20 Mar 17 nicklas 956             jsonMessages.add(permissionCheck);
4406 20 Mar 17 nicklas 957           }
4406 20 Mar 17 nicklas 958         }
4406 20 Mar 17 nicklas 959       }      
4406 20 Mar 17 nicklas 960     }
4406 20 Mar 17 nicklas 961     if (jsonMessages.size() == 0) jsonMessages.add("Ok");
4406 20 Mar 17 nicklas 962     json.put("messages", jsonMessages);
4406 20 Mar 17 nicklas 963     return json;
4406 20 Mar 17 nicklas 964   }
4514 01 Jun 17 nicklas 965   
4514 01 Jun 17 nicklas 966   public JSONObject checkDisabledPlugin(DbControl dc, String clazz,
4514 01 Jun 17 nicklas 967     PermissionOptions permissions, boolean createIfMissing)
4514 01 Jun 17 nicklas 968   {
4514 01 Jun 17 nicklas 969     JSONObject json = new JSONObject();
4514 01 Jun 17 nicklas 970     JSONArray jsonMessages = new JSONArray();
4514 01 Jun 17 nicklas 971     json.put("itemType", Item.PLUGINDEFINITION.name());
4514 01 Jun 17 nicklas 972     json.put("name", clazz);
4514 01 Jun 17 nicklas 973     
4514 01 Jun 17 nicklas 974     try
4514 01 Jun 17 nicklas 975     {
4514 01 Jun 17 nicklas 976       PluginDefinition plugin = PluginDefinition.getByClassName(dc, clazz);
4514 01 Jun 17 nicklas 977       json.put("id", plugin.getId());
4514 01 Jun 17 nicklas 978       json.put("name", plugin.getName());
4514 01 Jun 17 nicklas 979       json.put("status", "ok"); // For now -- more checks below
4514 01 Jun 17 nicklas 980       
4514 01 Jun 17 nicklas 981       if (!plugin.isDisabled())
4514 01 Jun 17 nicklas 982       {
4514 01 Jun 17 nicklas 983         if (createIfMissing)
4514 01 Jun 17 nicklas 984         {
4514 01 Jun 17 nicklas 985           plugin.setDisabled(true);
4514 01 Jun 17 nicklas 986           if (jsonMessages.size() == 0) jsonMessages.add("Fixed");
4514 01 Jun 17 nicklas 987         }
4514 01 Jun 17 nicklas 988         else
4514 01 Jun 17 nicklas 989         {
4514 01 Jun 17 nicklas 990           jsonMessages.add("Should be disabled");
4514 01 Jun 17 nicklas 991           json.put("status", "incomplete");
4514 01 Jun 17 nicklas 992         }
4514 01 Jun 17 nicklas 993       }
4514 01 Jun 17 nicklas 994       
4514 01 Jun 17 nicklas 995       if (permissions != null && !permissions.checkPermissions(plugin))
4514 01 Jun 17 nicklas 996       {
4514 01 Jun 17 nicklas 997         if (createIfMissing)
4514 01 Jun 17 nicklas 998         {
4514 01 Jun 17 nicklas 999           permissions.applyPermissions(plugin);
4514 01 Jun 17 nicklas 1000           if (jsonMessages.size() == 0) jsonMessages.add("Fixed");
4514 01 Jun 17 nicklas 1001         }
4514 01 Jun 17 nicklas 1002         else
4514 01 Jun 17 nicklas 1003         {
4514 01 Jun 17 nicklas 1004           json.put("status", "incomplete");
4514 01 Jun 17 nicklas 1005           jsonMessages.add(permissions.getMessage());
4514 01 Jun 17 nicklas 1006         }
4514 01 Jun 17 nicklas 1007       }
4514 01 Jun 17 nicklas 1008     }
4514 01 Jun 17 nicklas 1009     catch (ItemNotFoundException ex)
4514 01 Jun 17 nicklas 1010     {
4514 01 Jun 17 nicklas 1011       jsonMessages.add("Not installed");
4514 01 Jun 17 nicklas 1012       json.put("status", "error");
4514 01 Jun 17 nicklas 1013     }
4514 01 Jun 17 nicklas 1014     
4514 01 Jun 17 nicklas 1015     if (jsonMessages.size() == 0) jsonMessages.add("Ok");
4514 01 Jun 17 nicklas 1016     json.put("messages", jsonMessages);
4514 01 Jun 17 nicklas 1017     return json;
4514 01 Jun 17 nicklas 1018   }
4406 20 Mar 17 nicklas 1019
4515 01 Jun 17 nicklas 1020   public JSONObject checkRawDataType(DbControl dc, String name)
4515 01 Jun 17 nicklas 1021   {
4515 01 Jun 17 nicklas 1022     JSONObject json = new JSONObject();
4515 01 Jun 17 nicklas 1023     JSONArray jsonMessages = new JSONArray();
4515 01 Jun 17 nicklas 1024     json.put("itemType", "RAWDATATYPE");
4515 01 Jun 17 nicklas 1025     json.put("name", name);
4515 01 Jun 17 nicklas 1026     json.put("status", "ok"); // For now -- more checks below
4515 01 Jun 17 nicklas 1027     
4515 01 Jun 17 nicklas 1028     RawDataType rdt = RawDataTypes.getRawDataType(name);
4515 01 Jun 17 nicklas 1029     if (rdt == null)
4515 01 Jun 17 nicklas 1030     {
4515 01 Jun 17 nicklas 1031       jsonMessages.add("Not found");
4515 01 Jun 17 nicklas 1032       json.put("status", "error");
4515 01 Jun 17 nicklas 1033     }
4515 01 Jun 17 nicklas 1034     else
4515 01 Jun 17 nicklas 1035     {
4515 01 Jun 17 nicklas 1036       json.put("name", rdt.getName());
4515 01 Jun 17 nicklas 1037     }
4515 01 Jun 17 nicklas 1038     
4515 01 Jun 17 nicklas 1039     if (jsonMessages.size() == 0) jsonMessages.add("Ok");
4515 01 Jun 17 nicklas 1040     json.put("messages", jsonMessages);
4515 01 Jun 17 nicklas 1041     return json;
4515 01 Jun 17 nicklas 1042   }
4515 01 Jun 17 nicklas 1043   
4406 20 Mar 17 nicklas 1044   /**
4735 05 Apr 18 nicklas 1045     Create a platform variant with the given options. The platform is created in
4735 05 Apr 18 nicklas 1046     a separate transaction.
4735 05 Apr 18 nicklas 1047     @since 1.2
4735 05 Apr 18 nicklas 1048   */
4735 05 Apr 18 nicklas 1049   public PlatformVariant createPlatform(SessionControl sc, Rawdatatype rawType)
4735 05 Apr 18 nicklas 1050   {
4735 05 Apr 18 nicklas 1051     PlatformVariant pv = null;
7008 25 Jan 23 nicklas 1052     Platform p = null;
6779 17 Jun 22 nicklas 1053     DbControl dc = sc.newDbControl("Relax: install");
4735 05 Apr 18 nicklas 1054     try
4735 05 Apr 18 nicklas 1055     {
7008 25 Jan 23 nicklas 1056       try
7008 25 Jan 23 nicklas 1057       {
7008 25 Jan 23 nicklas 1058         p = rawType.getPlatform(dc);
7008 25 Jan 23 nicklas 1059       }
7008 25 Jan 23 nicklas 1060       catch (ItemNotFoundException ex)
7008 25 Jan 23 nicklas 1061       {
7008 25 Jan 23 nicklas 1062         p = Platform.getNew(dc, rawType.getPlatformId(), 1);
7008 25 Jan 23 nicklas 1063         p.setName(rawType.getPlatformName());
7008 25 Jan 23 nicklas 1064         dc.saveItem(p);
7008 25 Jan 23 nicklas 1065       }
7008 25 Jan 23 nicklas 1066       
4735 05 Apr 18 nicklas 1067       pv = PlatformVariant.getNew(dc, p, rawType.getVariantId(), 1);
4735 05 Apr 18 nicklas 1068       pv.setName(rawType.getName());
4735 05 Apr 18 nicklas 1069       dc.saveItem(pv);
4735 05 Apr 18 nicklas 1070
4735 05 Apr 18 nicklas 1071       dc.commit();
4735 05 Apr 18 nicklas 1072     }
4735 05 Apr 18 nicklas 1073     finally
4735 05 Apr 18 nicklas 1074     {
4735 05 Apr 18 nicklas 1075       if (dc != null) dc.close();
4735 05 Apr 18 nicklas 1076     }
4735 05 Apr 18 nicklas 1077     return pv;
4735 05 Apr 18 nicklas 1078   }
4735 05 Apr 18 nicklas 1079
4735 05 Apr 18 nicklas 1080   
4735 05 Apr 18 nicklas 1081   /**
4735 05 Apr 18 nicklas 1082     Check for an existing platform (variant) with the given options.
4735 05 Apr 18 nicklas 1083     A JSONObject is returned with the result. The following 
4735 05 Apr 18 nicklas 1084     keys are used:
4735 05 Apr 18 nicklas 1085     <ul>
4735 05 Apr 18 nicklas 1086     <li>itemType: PLATFORMVARIANT
4735 05 Apr 18 nicklas 1087     <li>name: The name of the platform variant
4735 05 Apr 18 nicklas 1088     <li>id: The id of the platform variant if it exists
4735 05 Apr 18 nicklas 1089     <li>status: ok, error, or missing
4735 05 Apr 18 nicklas 1090     <li>message: A descriptive message in case of an error
4735 05 Apr 18 nicklas 1091     </ul>
4735 05 Apr 18 nicklas 1092     @since 1.2
4735 05 Apr 18 nicklas 1093   */
4735 05 Apr 18 nicklas 1094   public JSONObject checkPlatform(DbControl dc, Rawdatatype rawType, 
4735 05 Apr 18 nicklas 1095     boolean createIfMissing)
4735 05 Apr 18 nicklas 1096   {
4735 05 Apr 18 nicklas 1097   
4735 05 Apr 18 nicklas 1098     JSONObject json = new JSONObject();
4735 05 Apr 18 nicklas 1099     JSONArray jsonMessages = new JSONArray();
4735 05 Apr 18 nicklas 1100     json.put("itemType", Item.PLATFORMVARIANT.name());
4735 05 Apr 18 nicklas 1101     json.put("name", rawType.getName());
4735 05 Apr 18 nicklas 1102     
4735 05 Apr 18 nicklas 1103     List<PlatformVariant> result = rawType.list(dc);
4735 05 Apr 18 nicklas 1104     if (result.size() == 0)
4735 05 Apr 18 nicklas 1105     {
4735 05 Apr 18 nicklas 1106       if (createIfMissing)
4735 05 Apr 18 nicklas 1107       {
4735 05 Apr 18 nicklas 1108         PlatformVariant pv = createPlatform(dc.getSessionControl(), rawType);
4735 05 Apr 18 nicklas 1109         json.put("id", pv.getId());
4735 05 Apr 18 nicklas 1110         json.put("status", "ok");
4735 05 Apr 18 nicklas 1111         jsonMessages.add("Created");
4735 05 Apr 18 nicklas 1112       }
4735 05 Apr 18 nicklas 1113       else
4735 05 Apr 18 nicklas 1114       {
4735 05 Apr 18 nicklas 1115         json.put("status", "missing");
4735 05 Apr 18 nicklas 1116         jsonMessages.add("Not found");
4735 05 Apr 18 nicklas 1117       }
4735 05 Apr 18 nicklas 1118     }
4735 05 Apr 18 nicklas 1119     else if (result.size() > 1)
4735 05 Apr 18 nicklas 1120     {
4735 05 Apr 18 nicklas 1121       json.put("status", "error");
4735 05 Apr 18 nicklas 1122       jsonMessages.add("Found > 1 platform");
4735 05 Apr 18 nicklas 1123     }
4735 05 Apr 18 nicklas 1124     else
4735 05 Apr 18 nicklas 1125     {
4735 05 Apr 18 nicklas 1126       PlatformVariant pv = result.get(0);
4735 05 Apr 18 nicklas 1127       Platform p = pv.getPlatform();
4735 05 Apr 18 nicklas 1128       json.put("id", pv.getId());
4735 05 Apr 18 nicklas 1129       json.put("status", "ok"); // For now -- more checks below
4735 05 Apr 18 nicklas 1130       
4735 05 Apr 18 nicklas 1131       if (!pv.getExternalId().equals(rawType.getVariantId()))
4735 05 Apr 18 nicklas 1132       {
4735 05 Apr 18 nicklas 1133         json.put("status", "error");
4735 05 Apr 18 nicklas 1134         jsonMessages.add("Should have '" + rawType.getVariantId() + "' as external id.");
4735 05 Apr 18 nicklas 1135       }
4735 05 Apr 18 nicklas 1136     }
4735 05 Apr 18 nicklas 1137     
4735 05 Apr 18 nicklas 1138     if (jsonMessages.size() == 0) jsonMessages.add("Ok");
4735 05 Apr 18 nicklas 1139     json.put("messages", jsonMessages);
4735 05 Apr 18 nicklas 1140     return json;
4735 05 Apr 18 nicklas 1141   
4735 05 Apr 18 nicklas 1142   }
4735 05 Apr 18 nicklas 1143
4735 05 Apr 18 nicklas 1144   /**
5176 05 Dec 18 nicklas 1145     Store options for enumerated annotation types.
5176 05 Dec 18 nicklas 1146   */
5176 05 Dec 18 nicklas 1147   static class ValueOptions
5176 05 Dec 18 nicklas 1148   {
5176 05 Dec 18 nicklas 1149     private final Object[] options;
5176 05 Dec 18 nicklas 1150     
5176 05 Dec 18 nicklas 1151     /**
5176 05 Dec 18 nicklas 1152       The annotation type is an enumerated annotation type with the following options.
5176 05 Dec 18 nicklas 1153     */
5176 05 Dec 18 nicklas 1154     ValueOptions(Object... options)
5176 05 Dec 18 nicklas 1155     {
5176 05 Dec 18 nicklas 1156       this.options = options;
5176 05 Dec 18 nicklas 1157     }
5176 05 Dec 18 nicklas 1158     
5176 05 Dec 18 nicklas 1159     boolean isEnumeration()
5176 05 Dec 18 nicklas 1160     {
5176 05 Dec 18 nicklas 1161       return options != null;
5176 05 Dec 18 nicklas 1162     }
5176 05 Dec 18 nicklas 1163     
5176 05 Dec 18 nicklas 1164     /**
5176 05 Dec 18 nicklas 1165       Get the options as a List.
5176 05 Dec 18 nicklas 1166     */
5176 05 Dec 18 nicklas 1167     List<?> getList()
5176 05 Dec 18 nicklas 1168     {
5176 05 Dec 18 nicklas 1169       return Arrays.asList(options);
5176 05 Dec 18 nicklas 1170     }
5176 05 Dec 18 nicklas 1171     
5176 05 Dec 18 nicklas 1172     /**
5176 05 Dec 18 nicklas 1173       Get the options as an array.
5176 05 Dec 18 nicklas 1174     */
5176 05 Dec 18 nicklas 1175     Object[] getArray()
5176 05 Dec 18 nicklas 1176     {
5176 05 Dec 18 nicklas 1177       return options;
5176 05 Dec 18 nicklas 1178     }
5176 05 Dec 18 nicklas 1179     
5176 05 Dec 18 nicklas 1180     /**
5176 05 Dec 18 nicklas 1181       Add options missing in the current annotation type.
5176 05 Dec 18 nicklas 1182     */
5176 05 Dec 18 nicklas 1183     void applyEnumeration(AnnotationType at)
5176 05 Dec 18 nicklas 1184     {
5176 05 Dec 18 nicklas 1185       List<Object> values = new ArrayList<Object>(at.getValues());
5176 05 Dec 18 nicklas 1186       for (Object opt : options)
5176 05 Dec 18 nicklas 1187       {
5176 05 Dec 18 nicklas 1188         if (!values.contains(opt)) values.add(opt);
5176 05 Dec 18 nicklas 1189       }
5176 05 Dec 18 nicklas 1190       at.setValues(values);
5176 05 Dec 18 nicklas 1191     }
5176 05 Dec 18 nicklas 1192   }
5176 05 Dec 18 nicklas 1193   /**
4406 20 Mar 17 nicklas 1194     Store permissions that can be applied to shareable items.
4406 20 Mar 17 nicklas 1195   */
4406 20 Mar 17 nicklas 1196   static class PermissionOptions
4406 20 Mar 17 nicklas 1197   {
4406 20 Mar 17 nicklas 1198     private Map<Group, Permission> groupPermissions;
4406 20 Mar 17 nicklas 1199     private Map<Project, Permission> projectPermissions;
4406 20 Mar 17 nicklas 1200     private String message;
4406 20 Mar 17 nicklas 1201     
4406 20 Mar 17 nicklas 1202     PermissionOptions()
4406 20 Mar 17 nicklas 1203     {
4406 20 Mar 17 nicklas 1204       groupPermissions = new HashMap<Group, Permission>();
4406 20 Mar 17 nicklas 1205       projectPermissions = new HashMap<Project, Permission>();
4406 20 Mar 17 nicklas 1206     }
4406 20 Mar 17 nicklas 1207   
4406 20 Mar 17 nicklas 1208     /**
4406 20 Mar 17 nicklas 1209       Set a permission for the given group.
4406 20 Mar 17 nicklas 1210     */
4406 20 Mar 17 nicklas 1211     void set(Group g, Permission p)
4406 20 Mar 17 nicklas 1212     {
4406 20 Mar 17 nicklas 1213       groupPermissions.put(g, p);
4406 20 Mar 17 nicklas 1214     }
4406 20 Mar 17 nicklas 1215   
4406 20 Mar 17 nicklas 1216     /**
4406 20 Mar 17 nicklas 1217       Set a permission for the given project.
4406 20 Mar 17 nicklas 1218     */
4406 20 Mar 17 nicklas 1219     void set(Project pr, Permission p)
4406 20 Mar 17 nicklas 1220     {
4406 20 Mar 17 nicklas 1221       projectPermissions.put(pr, p);
4406 20 Mar 17 nicklas 1222     }
4406 20 Mar 17 nicklas 1223   
4406 20 Mar 17 nicklas 1224     /**
4406 20 Mar 17 nicklas 1225       Check if the given item includes at least all the required permissions.
4406 20 Mar 17 nicklas 1226       @return TRUE if all permissions are ok, FALSE if not (call getMessage())
4406 20 Mar 17 nicklas 1227       to get more information.
4406 20 Mar 17 nicklas 1228     */
4406 20 Mar 17 nicklas 1229     boolean checkPermissions(SharedItem item)
4406 20 Mar 17 nicklas 1230     {
4406 20 Mar 17 nicklas 1231       ProjectKey pKey = item.getProjectKey();
4406 20 Mar 17 nicklas 1232       for (Map.Entry<Project, Permission> entry : projectPermissions.entrySet())
4406 20 Mar 17 nicklas 1233       {
4406 20 Mar 17 nicklas 1234         Project pr = entry.getKey();
4406 20 Mar 17 nicklas 1235         Permission p = entry.getValue();
4406 20 Mar 17 nicklas 1236         
4406 20 Mar 17 nicklas 1237         Set<Permission> permissions = pKey != null ? pKey.getPermissions(pr) : null;
4406 20 Mar 17 nicklas 1238         if (p == null)
4406 20 Mar 17 nicklas 1239         {
4406 20 Mar 17 nicklas 1240           // The item should not be shared to project 'pr'
4406 20 Mar 17 nicklas 1241           if (permissions != null && permissions.size() > 0)
4406 20 Mar 17 nicklas 1242           {
4406 20 Mar 17 nicklas 1243             message = "Should not be shared to project: " + pr.getName() + " (" + permissions + ")";
4406 20 Mar 17 nicklas 1244             return false;
4406 20 Mar 17 nicklas 1245           }
4406 20 Mar 17 nicklas 1246         }
4406 20 Mar 17 nicklas 1247         else
4406 20 Mar 17 nicklas 1248         {
4406 20 Mar 17 nicklas 1249           // The item should be shared to project 'pr' with permission 'p'
4406 20 Mar 17 nicklas 1250           if (pKey == null || !permissions.contains(p))
4406 20 Mar 17 nicklas 1251           {
4406 20 Mar 17 nicklas 1252             message = "Not shared to project: " + pr.getName() + " (" + p + ")";
4406 20 Mar 17 nicklas 1253             return false;
4406 20 Mar 17 nicklas 1254           }
4406 20 Mar 17 nicklas 1255         }
4406 20 Mar 17 nicklas 1256       }
4406 20 Mar 17 nicklas 1257       ItemKey key = item.getItemKey();
4406 20 Mar 17 nicklas 1258       for (Map.Entry<Group, Permission> entry : groupPermissions.entrySet())
4406 20 Mar 17 nicklas 1259       {
4406 20 Mar 17 nicklas 1260         Group g = entry.getKey();
4406 20 Mar 17 nicklas 1261         Permission p = entry.getValue();
4406 20 Mar 17 nicklas 1262         
4406 20 Mar 17 nicklas 1263         Set<Permission> permissions = key != null ? key.getPermissions(g) : null;
4406 20 Mar 17 nicklas 1264         if (p == null)
4406 20 Mar 17 nicklas 1265         {
4406 20 Mar 17 nicklas 1266           // The item should not be shared to group 'g'
4406 20 Mar 17 nicklas 1267           if (permissions != null && permissions.size() > 0)
4406 20 Mar 17 nicklas 1268           {
4406 20 Mar 17 nicklas 1269             message = "Should not be shared to group: " + g.getName() + " (" + permissions + ")";
4406 20 Mar 17 nicklas 1270             return false;
4406 20 Mar 17 nicklas 1271           }
4406 20 Mar 17 nicklas 1272         }
4406 20 Mar 17 nicklas 1273         else
4406 20 Mar 17 nicklas 1274         {
4406 20 Mar 17 nicklas 1275           // The item should be shared to group 'g' with permission 'p'
4406 20 Mar 17 nicklas 1276           if (key == null || !key.getPermissions(g).contains(p))
4406 20 Mar 17 nicklas 1277           {
4406 20 Mar 17 nicklas 1278             message = "Not shared to group: " + g.getName() + " (" + p + ")";
4406 20 Mar 17 nicklas 1279             return false;
4406 20 Mar 17 nicklas 1280           }
4406 20 Mar 17 nicklas 1281         }
4406 20 Mar 17 nicklas 1282   
4406 20 Mar 17 nicklas 1283       }
4406 20 Mar 17 nicklas 1284       return true;
4406 20 Mar 17 nicklas 1285     }
4406 20 Mar 17 nicklas 1286     
4406 20 Mar 17 nicklas 1287     /**
4406 20 Mar 17 nicklas 1288       More information about missing permission from the checkPermissions() method.
4406 20 Mar 17 nicklas 1289     */
4406 20 Mar 17 nicklas 1290     String getMessage()
4406 20 Mar 17 nicklas 1291     {
4406 20 Mar 17 nicklas 1292       return message;
4406 20 Mar 17 nicklas 1293     }
4406 20 Mar 17 nicklas 1294   
4406 20 Mar 17 nicklas 1295     /**
4406 20 Mar 17 nicklas 1296       Apply all permissions to the given item.
4406 20 Mar 17 nicklas 1297     */
4406 20 Mar 17 nicklas 1298     void applyPermissions(SharedItem item)
4406 20 Mar 17 nicklas 1299     {
4406 20 Mar 17 nicklas 1300       MultiPermissions mp = new MultiPermissions(Collections.singleton(item));
4406 20 Mar 17 nicklas 1301       for (Map.Entry<Group, Permission> entry : groupPermissions.entrySet())
4406 20 Mar 17 nicklas 1302       {
4406 20 Mar 17 nicklas 1303         Group g = entry.getKey();
4406 20 Mar 17 nicklas 1304         Permission p = entry.getValue();
4406 20 Mar 17 nicklas 1305         if (p == null)
4406 20 Mar 17 nicklas 1306         {
4406 20 Mar 17 nicklas 1307           mp.setPermissions(g, null);
4406 20 Mar 17 nicklas 1308         }
4406 20 Mar 17 nicklas 1309         else
4406 20 Mar 17 nicklas 1310         {
4406 20 Mar 17 nicklas 1311           mp.addPermissions(g, Collections.singleton(p));
4406 20 Mar 17 nicklas 1312         }
4406 20 Mar 17 nicklas 1313       }
4406 20 Mar 17 nicklas 1314       for (Map.Entry<Project, Permission> entry : projectPermissions.entrySet())
4406 20 Mar 17 nicklas 1315       {
4406 20 Mar 17 nicklas 1316         Project pr = entry.getKey();
4406 20 Mar 17 nicklas 1317         Permission p = entry.getValue();
4406 20 Mar 17 nicklas 1318         if (p == null)
4406 20 Mar 17 nicklas 1319         {
4406 20 Mar 17 nicklas 1320           mp.setPermissions(pr, null);
4406 20 Mar 17 nicklas 1321         }
4406 20 Mar 17 nicklas 1322         else
4406 20 Mar 17 nicklas 1323         {
4406 20 Mar 17 nicklas 1324           mp.addPermissions(pr, Collections.singleton(p));
4406 20 Mar 17 nicklas 1325         }
4406 20 Mar 17 nicklas 1326       }
4406 20 Mar 17 nicklas 1327       mp.updateKeys(item.getDbControl());
4406 20 Mar 17 nicklas 1328     }
4406 20 Mar 17 nicklas 1329   }
4350 10 Feb 17 nicklas 1330 }