Vanliga misstag

1. getNew()-metoden

Måste ge ett värde till alla properties som är deklarerade med not-null genom:

Anledningen är att vi vill få en InvalidDataException direkt och inte något databasfel vid DbControl.commit(). T.ex. ska nedanstående kod fungera:

Item i = Item.getNew(dc);
dc.saveItem(i);
dc.commit();
// Se även punkt 2. test_create()
ReporterType.getNew:
public static ReporterType getNew(DbControl dc)
   throws PermissionDeniedException, BaseException
{
   return dc.newItem(ReporterType.class);
}
// Saknar setName()
Directory.getNew:
public static Directory getNew(DbControl dc)
   throws BaseException
{
Directory d = dc.newItem(Directory.class);
   d.setParent(Directory.getById(dc, SystemItems.getId(Directory.ROOT)));
   return d;
}
// Saknar setName()
// Använd DirectoryData istället för Directory, eller...
// Skicka med ett Directory som parameter (se t.ex. File.getNew nedan)
File.getNew:
public static File getNew(DbControl dc, Directory directory)
   throws BaseException
{
   File file = dc.newItem(File.class);
   file.setAction(File.Action.NOTHING);
   file.setLocation(Location.OFFLINE);
   file.setDirectory(directory);
   return file;
}
// Saknar setName()

Lämpligt värde för name är "New reporter type", "New file", etc.

2. test_create()

För att testa att getNew() fungerar enligt ovan bör test_create() konstrueras så att man kan testa både med och utan att man sätter några värden på en ny item. T.ex:

TestRole.test_create:
static int test_create(boolean setAll)
{
   if (!TestUtil.hasPermission(Permission.CREATE, Item.ROLE)) return 0;
   int id = 0;
   DbControl dc = null;
   try
   {
      dc = TestUtil.getDbControl();
      Role r = Role.getNew(dc);
      if (setAll)
      {
         r.setName("Test role");
         r.setDescription("Added at "+new Date());
      }
      dc.saveItem(r);
      dc.commit();
      id = r.getId();
      write_item(0, r);
      write("--Create role OK");
   }
   catch (Throwable ex)
   {
      write("--Create role FAILED");
      ex.printStackTrace();
      ok = false;
   }
   finally
   {
      if (dc != null) dc.close();
   }
   return id;
}
// Notera parameters setAll (markerat med fet-stil)

3. set-metoder

User.setLogin:
public void setLogin(String login)
   throws PermissionDeniedException, InvalidDataException
{
   checkPermission(Permission.WRITE);
   getData().setLogin(StringUtil.setNotNullString(login, "login", MAX_LOGIN_LENGTH));
}
// Inga fel
File.setMimeType:
public void setMimeType(String mimeType)
   throws PermissionDeniedException
{
   checkPermission(Permission.WRITE);
   getData().setMimeType(mimeType);
}
// Validerar ej max-läng på mimeType (null är tillåtet)
// Använd t.ex. StringUtil.setNullableString(...)
File.setLocation:
public void setLocation(Location location) 
   throws PermissionDeniedException
{
   checkPermission(Permission.WRITE);
   getData().setLocation(location.getValue());
}
// Validerar ej att location != null
File.setFileType:
public void setFileType(FileType filetype)
   throws PermissionDeniedException
{
   checkPermission(Permission.WRITE);
   getData().setFileType(filetype.getData());
}
// null är tillåtet men det måste kollas innan filetype.getData(). Använd ?-operatorn.

För validering av stränglängd deklareras public static final int MAX_XXX_LENGTH i Data-klasserna och i Item-klasserna:

UserData:
   public static final int MAX_LOGIN_LENGTH = 255;
User:
   public static final int MAX_LOGIN_LENGTH = UserData.MAX_LOGIN_LENGTH;
File.setDirectory:
public void setDirectory(Directory directory)
   throws PermissionDeniedException
{
   checkPermission(Permission.WRITE);
   getData().setDirectory(directory.getData());
}
// Validerar ej att directory != null
// Kontrollerar ej USE-permission på directory
Software.setSoftwareType:
public void setSoftwareType(SoftwareType hardwaretype)
   throws PermissionDeniedException, InvalidUseOfNullException
{
   if (hardwaretype == null) throw new InvalidUseOfNullException("hardwaretype");
   hardwaretype.checkPermission(Permission.USE);
   getData().setSoftwareType(hardwaretype.getData());
}
// Saknar checkPermission(Permission.WRITE)
Directory.setParent:
public void setParent(Directory parent)
   throws PermissionDeniedException, InvalidUseOfNullException
{
   if (parent != null)
   {
      parent.checkPermission(Permission.WRITE);
      getData().setParent(parent.getData());
   }
   else
   {
      throw new InvalidUseOfNullException("A directory must have a parent directory");
   }
}
// "Felaktig" ordning på kontrollerna

4. get-metoder

Directory.getParent:
public Directory getParent() 
   throws PermissionDeniedException, BaseException
{
   Directory parent = null;
   if(getData().getParent() != null)
   {
      parent = getDbControl().getItem(Directory.class, getData().getParent());
      parent.checkPermission(Permission.READ);
   } 
   return parent;
}
// Onödig kontroll av != null
// Onödig kontroll av Permission.READ

5. getQuery() och initPermissions()

Om klassen ärver ifrån OwnedItem, SharedItem eller CommonItem behöver man normalt inte göra något speciellt med dessa metoder. initPermissions() behövs inte alls, och getQuery() blir enkel:

Client.getQuery:
public static Query getQuery(DbControl dbControl)
   throws BaseException
{
   return new ItemQuery(dbControl, Client.class);
}

Om man ärver ifrån BasicItem kan det bli mycket mer komplierat. Man måste själv se till att getQuery() inte returnerar objekt som man inte har READ-permission till. Detta måste synkas med initPermissions().

Group.getQuery:
public static Query getQuery(DbControl dc)
   throws BaseException
{
   Query query = new ItemQuery(dc, Group.class);
   SessionControl sc = dc.getSessionControl();
   if (!sc.hasPermission(Permission.READ, Item.GROUP))
   {
      Expression id = Expressions.property(query.rootAlias()+".id");
      if (sc.isLoggedIn())
      {
         // Load groups where the logged in user is a member
         query.addPermanent(Restrictions.in(id, Expressions.parameter("groups")));
         query.setPermanentParameter("groups", sc.getGroups());
      }
      else
      {
         // Do not load any groups if not logged in
         query.addPermanent(Restrictions.neq(id, id));
      }
   }
   return query;
}

Group.initPermissions:
void initPermissions(int granted, int denied)
   throws BaseException
{
   if (isSystemItem()) 
   {
      denied |= Permission.deny(Permission.DELETE, Permission.CREATE);
   }
   if (getSessionControl().isMemberOf(this))
   {
      granted |= Permission.grant(Permission.READ);
   }
   super.initPermissions(granted, denied);
}

Notera att BasicItem.initPermissions() ger permissions enligt de roller man är tilldelad så även om man inte behöver ändra på detta så måste man ta hänsyn till den kontrollen i getQuery().

Abc.getQuery:
public static Query getQuery(DbControl dc)
   throws BaseException
{
   Query query = new ItemQuery(dc, Abc.class);
   SessionControl sc = dc.getSessionControl();
   if (!sc.hasPermission(Permission.READ, Item.ABC))
   {
      Expression id = Expressions.property(query.rootAlias()+".id");
      // Do not load any abc if READ permission is missing
      query.addPermanent(Restrictions.neq(id, id));
   }
   return query;
}

Om man har en klass med parent/child relation så är det lämpligt att getQuery() får en extra parameter:

Help.getQuery:
public static Query getQuery(DbControl dc, Client client)
   throws BaseException
{
   Query query = new ItemQuery(dc, Help.class);
   if (client == null)
   { 
      if (!dc.getSessionControl().hasPermission(Permission.READ, Item.CLIENT))
      {
         // Do not return any help
         Expression id = Expressions.property(query.rootAlias()+".id");
         query.addPermanent(Restrictions.neq(id, id));
      }
   }
   else
   {
      // Return help for the specified client
      query.addPermanent(
         Restrictions.eq(
            Expressions.property(query.rootAlias()+".client"), 
            Expressions.integer(client.getId())
         )
      );
   }
   return query;
}
Help.initPermissions:
void initPermissions(int granted, int denied)
   throws BaseException
{
   Client c = getClient();
   if (c.hasPermission(Permission.READ))
   {
      granted |= Permission.grant(Permission.READ);
   }
   if (c.hasPermission(Permission.WRITE))
   {
      granted |= Permission.grant(Permission.WRITE, Permission.DELETE, Permission.CREATE);
   }
   super.initPermissions(granted, denied);
}

6. Följ kodningsreglerna