org.tentackle.appworx
Class ContextDb

java.lang.Object
  extended by org.tentackle.appworx.ContextDb
All Implemented Interfaces:
Serializable, Cloneable, Comparable<ContextDb>

public class ContextDb
extends Object
implements Comparable<ContextDb>, Serializable, Cloneable

The application's database context.

Basically, this is a decorator for a logical Db-connection. All AppDbObjects refer to a ContextDb instead of a Db. The ContextDb carries the application's higher level database context which can be used to implement the so-called multitenancy. If your application is not multitenant, you don't have to pay further attention to it.

For multitenant applications, however, the ContextDb can be extended to hold the ID(s) of the object(s) describing the context. Because an AppDbObject carries a reference to that context, it can serve as a root for a logical data space. For example, a AppDbObject.selectAllInContext() of accounts will deliver only the accounts belonging to that particular tenant.
All classes depending on those extended contexts must also implement an appropriate extension of ContextDependable. By further subclassing, a multitenancy hierarchy can be achieved. For example, in a financial accounting system, the hierarchy could be: TenantDb -> FiscalYearDb -> BookDb with corresponding TenantDependable -> FiscalYearDependable -> BookDependable. It is recommended to subclass AppDbObject accordingly, i.e. TenantDbObject -> FiscalYearDbObject -> BookDbObject and/or to override the methods in ContextDependable by applying multiple inheritance emulation via the Wurbelizer.

Note: the wurblets support multitenancy by means of the options CONTEXT, CONTEXTID and UNIQUE.

Author:
harald
See Also:
Serialized Form

Constructor Summary
ContextDb(Db db)
          Creates a default context.
 
Method Summary
static void applyToCollection(ContextDb contextDb, Collection<? extends ContextDependable> list)
          Sets the context in a list of ContextDependables.
static void applyToContextDependable(ContextDb contextDb, ContextDependable obj)
          Sets the context in a ContextDependable, if not null.
 void assertPermissions()
          Asserts that this context is allowed to be used by the current user.
If it is not allowed, a DbRuntimeException is thrown.
 ContextDb clone()
          ContextDbs may be cloned (e.g.
 int compareTo(ContextDb otherContextDb)
          Contexts must be comparable.
 boolean equals(Object obj)
          Overridden to allow for checks whether contexts are equal.
 AppUserInfo getAppUserInfo()
          AppDbObjects should be connected to a Db via AppUserInfo, not UserInfo.
 long getContextId()
          Gets the ID of the context object.
 AppDbObject getContextObject()
          Gets the object that spans this context.
 Db getDb()
          Gets the db connection of that context
 String getInfo()
          Get the long description of this context.
 int hashCode()
          Returns a hash code value for the object.
 boolean isWithinContext(long contextId, String contextClass)
          Determines whether this context belongs to an inheritance hierarchy that is created from a given context object.
 void setDb(Db db)
          Sets the db connection.
Used for objects traveling between the client and the server.
 String toString()
          Gets the string representation of this context.
 
Methods inherited from class java.lang.Object
finalize, getClass, notify, notifyAll, wait, wait, wait
 

Constructor Detail

ContextDb

public ContextDb(Db db)
Creates a default context.

Parameters:
db - the db connection
Method Detail

getDb

public Db getDb()
Gets the db connection of that context

Returns:
the db

setDb

public void setDb(Db db)
Sets the db connection.
Used for objects traveling between the client and the server. It is also checked that the user is allowed to use this context.

Parameters:
db - the db connection
See Also:
assertPermissions()

getAppUserInfo

public AppUserInfo getAppUserInfo()
                           throws ApplicationException
AppDbObjects should be connected to a Db via AppUserInfo, not UserInfo. The AppUserInfo extends the UserInfo by a SecurityManager.

Returns:
the AppUserInfo associated to the Db.
Throws:
ApplicationException - if Db does not provide AppUserInfo

assertPermissions

public void assertPermissions()
Asserts that this context is allowed to be used by the current user.
If it is not allowed, a DbRuntimeException is thrown. The default implementation does nothing.

Override the method in middle tier servers, for example in a hypothetical TenantContextDb:

  public void assertPermissions()  {
    if (DbGlobal.serverDb != null &&    // if in RMI server
        !getTenant().isUsageAllowed()) {
       throw new DbRuntimeException("malicious client tried to use context " + this);
    }
  }
 

Throws:
DbRuntimeException - if assertion failed

getContextObject

public AppDbObject getContextObject()
Gets the object that spans this context. The default implementation returns null. Must be overridden in subclasses.

Returns:
the root object, null if in default context

getContextId

public long getContextId()
Gets the ID of the context object. The default implementation returns 0. Must be overridden in subclasses.

Returns:
the object ID, 0 if in default context

isWithinContext

public boolean isWithinContext(long contextId,
                               String contextClass)
Determines whether this context belongs to an inheritance hierarchy that is created from a given context object.

The method is invoked from Security.evaluate(org.tentackle.appworx.ContextDb, int) to check whether a security rule applies to a given context. Note that contextClass is the basename of the context object's class, for example "Tenant" or "FiscalYear", and not the classname of the ContextDb.

The default implementation returns contextId == 0 || contextId == getContextId(). This is sufficient for zero or one level of context inheritance. For more than one level this method must be overwridden in each level. Example for a hypothetical "TenantContextDb":

  public boolean isWithinContext(long contextId, String contextClass) {
    if (contextClass != null && contextClass.equals("Tenant") && contextId == getContextId()) {
      return true;
    }
    return super.isWithinContext(contextId, contextClass);
  }
 
If the object IDs of the context objects are unique among all context entities the contextClass can be ignored and the method reduces to:
  public boolean isWithinContext(long contextId, String contextClass) {
    return contextId == getContextId() ||
           super.isWithinContext(contextId, contextClass);
  }
 

Parameters:
contextId - the object ID of a context object, 0 = default context
contextClass - the class basename of the context object, null = default context
Returns:
true if within that context, false if context does not apply

toString

public String toString()
Gets the string representation of this context. The default implementation returns the string of the context object, or the empty string (not the null-string!), if no such object, which is the case for the plain ContextDb.

Overrides:
toString in class Object
Returns:
the string

getInfo

public String getInfo()
Get the long description of this context. Used for logging, for example.

Returns:
the long info

compareTo

public int compareTo(ContextDb otherContextDb)
Contexts must be comparable. For example, the AppDbObjectCache may keep several instances of the same object in different contexts. The default implementation just compares the classes, then the ContextIds and then the db connections.

Specified by:
compareTo in interface Comparable<ContextDb>
Parameters:
otherContextDb - the context to compare this context to
Returns:
a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

equals

public boolean equals(Object obj)
Overridden to allow for checks whether contexts are equal. The default implementation just checks the classes, the contextIds and db connections for equality. Checking against the null object is allowed and will return false.

Overrides:
equals in class Object
Parameters:
obj - the object to check for equality
Returns:
true if this object is the same as the obj argument; false otherwise.
See Also:
Object.hashCode(), Hashtable

hashCode

public int hashCode()
Description copied from class: java.lang.Object
Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those provided by java.util.Hashtable.

The general contract of hashCode is:

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)

Overrides:
hashCode in class Object
Returns:
a hash code value for this object.
See Also:
Object.equals(java.lang.Object), Hashtable

clone

public ContextDb clone()
ContextDbs may be cloned (e.g. in QbfParameter to allow temporary change in the db-connection). The default implementation just invokes clone().

Overrides:
clone in class Object
Returns:
the cloned context
See Also:
Cloneable

applyToContextDependable

public static void applyToContextDependable(ContextDb contextDb,
                                            ContextDependable obj)
Sets the context in a ContextDependable, if not null.

Parameters:
contextDb - the database context
obj - the data object

applyToCollection

public static void applyToCollection(ContextDb contextDb,
                                     Collection<? extends ContextDependable> list)
Sets the context in a list of ContextDependables.

Parameters:
contextDb - the database context
list - the collection of data objects


Copyright © 2001-2008 Harald Krake, Bergstr. 48, 78098 Triberg, Germany, harald@krake.de