public final class AppContext
extends java.lang.Object
AppContext
is used to encapsulate the runtime environment.
To a first approximation the AppContext
is passed down to all
levels of the code and most significant classes contain a reference to an AppContext
.
Because Web applications are typically multi threaded
we wish to avoid static variables. The AppContext
is used to hold any information
that we would otherwise be tempted to have as static and any static methods usually need to take
an AppContext
as a parameter.
Though there is a high degree of dependence between AppContext
and most of
the code base we concentrate global dependencies within this Object which
reduces coupling to the classes contained within the
AppContext
such as the database connection.
Each page request will have an independent
AppContext
and short term state can be cached within in using the setAttribute
method. This data can be retrieved using the getAttribute
method.
The AppContext also acts as a composite policy object allowing different behaviours
to be selected depending on the environment.
This allows a policy object specific to a particular type of functionality (e.g. logging) to be retrieved using the getService(Class)
method (the class object for
the required interface/superclass is used as the key). e.g.
LoggerService lfac = conn.getService(LoggerService.class); Logger log = lfac.getLogger(getClass()) log.debug("Debug message");
Services all implement AppContextService
and can be pre-set using the setService(AppContextService)
method or they can be constructed dynamically by a call to makeObject(Class, String)
The FQCN of the class used to request the service is used as the identifying tag when lookup up the implementation class. If the located class is annotated with the PreRequisiteService
annotation
then the AppContext will attempt to ensure the referenced services are in place before calling the constructor of the requested service.
All services are cached as attributes so the same instance will be returned by subsequent calls to
getService(Class)
. Frequently AppContextService
s will be chained together with the currently installed implementation of a service holding a reference to the implementation it replaced and possibly
forwarding some requests to that nested version.
Key AppContextService
s include:
LoggerService
- application logging policy ConfigService
- configuration property policy SessionService
- user session and persistence DatabaseService
- database connection service
The AppContext class is final so all specialisations need to be implemented via AppContextService
s.
The AppContext encodes the conventions for constructing objects by reflection. A typical use might be:
TargetType t = conn.makeObject(TargetType.class,"tag-name");This uses the
getPropertyClass(Class, String)
method that looks for a class name in
a configuration property of the form
class.tag-name This may either be a full class-name or the name of a
classdef parameter e.g.
class.fred=myclass class.bill=myclass classdef.myclass=com.example.thingThe target type can be an interface or a superclass of desired object. If the target type is a non abstract class it will be used as the default if no class is configured using parameters. The AppContext will attempt various constructor signatures when creating an object in this way attempting to pass the tag-name and the AppContext. Some of these include the tag-name so its possible to refer to several instances of the same type by different tag-names. Factory classes that correspond to different database tables often follow this pattern, using the table name as the tag. If a class implements the
Tagged
interface the value returned by the Tagged.getTag()
method should be the same
as the tag used to construct the object.
AppContext c;
String param1 = c.getInitParameter("param1");
String param2 = c.getInitParameter("param2","Default value");
int int_param = c.getIntegerParameter("param3",13); // default to 13
These methods use an underlying ConfigService
.
try{
....
}catch(Exception e){
c.error(e,"An error occurred");
}
These are forwarded onto an underlying LoggerService
if one is available but converts the error to a fatal error otherwise.
Normally it is better to use a Logger
specific to
the class where the exception is caught unless reporting error from within a AppContextService
.
We will probably remove or reduce the visibility of the AppContext methods in the near future.
Modifier and Type | Field and Description |
---|---|
static java.lang.String |
CLASS_PREFIX |
static java.lang.String |
CLASSDEF_PROP_PREFIX |
static Feature |
CONTEXT_CACHE_FEATURE |
static Feature |
DATABASE_FEATURE |
static Feature |
TAG_CHECK_FEATURE |
Constructor and Description |
---|
AppContext() |
AppContext(java.util.Properties props) |
Modifier and Type | Method and Description |
---|---|
<T extends Contexed> |
canMakeContexedObject(java.lang.Class<T> clazz)
Method to check a class implements one of the supported constructors
for
canMakeContexedObject(Class) |
<T> boolean |
canMakeObject(java.lang.Class<T> clazz)
Method to check if a class implements one of the permitted constructors for
makeObject(Class) |
void |
clearAttributes() |
<S extends AppContextService<S>> |
clearService(java.lang.Class<S> clazz) |
void |
close()
Cleans up resources held by the
AppContext
The AppContextCleanup.cleanup() method is called on
each service in the reverse order that services were created. |
void |
error(java.lang.String errors)
Report an application error.
|
void |
error(java.lang.Throwable e,
java.lang.String text)
Report an application error.
|
java.lang.String |
expandText(java.lang.String text_to_expand)
perform config parameter expansion on a text fragment.
|
<T> java.lang.reflect.Constructor<T> |
findConstructor(java.lang.Class<T> clazz,
java.lang.Object... param)
Search for a matching constructor considering supertypes
|
<T> java.lang.reflect.Constructor<T> |
findConstructorFromParamSignature(java.lang.Class<T> clazz,
java.lang.Class... param)
Search for Constructor considering super-types
|
java.lang.Object |
getAttribute(java.lang.Object key)
method for returning Objects cached in the AppContext using setAttribute.
|
java.util.Map<java.lang.Object,java.lang.Object> |
getAttributes() |
boolean |
getBooleanParameter(java.lang.String name,
boolean def)
Check for a boolean parameter yes/on/true or no/off/false
|
<T> java.lang.Class<? extends T> |
getClassDef(java.lang.Class<T> template,
java.lang.String name) |
<T> java.lang.Class<? extends T> |
getClassFromName(java.lang.Class<T> template,
java.lang.Class<? extends T> default_class,
java.lang.String tag)
resolve a class-name into a class.
|
java.util.List<java.lang.Class> |
getClassList(java.lang.Class template,
java.lang.String name) |
<T> java.util.Map<java.lang.String,java.lang.Class> |
getClassMap(java.lang.Class<T> template)
Generate a map of tags to classes assignable to (or containing
an assignable
Composable Composite of) a target type
This will only find classes registered with the config service. |
double |
getDoubleParam(java.lang.String name,
double def) |
<E extends java.lang.Enum> |
getEnumParameter(java.lang.Class<E> clazz,
java.lang.String name,
E fallback) |
java.lang.String |
getExpandedProperty(java.lang.String name)
Query an environmental parameter with nested parameter expansion
|
java.lang.String |
getExpandedProperty(java.lang.String name,
java.lang.String def) |
java.lang.String |
getInitParameter(java.lang.String name)
Query environmental parameter.
|
java.lang.String |
getInitParameter(java.lang.String name,
java.lang.String fallback)
Query an environmental parameter returning a default value if not found
|
java.util.Hashtable<java.lang.String,java.lang.String> |
getInitParameters(java.lang.String prefix)
Get all environmental parameters starting with a given prefix.
|
int |
getIntegerParameter(java.lang.String name,
int def) |
long |
getLongParameter(java.lang.String name,
long def) |
java.util.Properties |
getProperties()
return a copy of the Service properties associated with the AppContext
|
<T> java.lang.Class<? extends T> |
getPropertyClass(java.lang.Class<T> template,
java.lang.Class<? extends T> default_class,
java.lang.String tag)
lookup a desired implementation class using the Config service.
|
<T> java.lang.Class<? extends T> |
getPropertyClass(java.lang.Class<T> template,
java.lang.String tag)
lookup a desired implementation class using the Config service.
|
<S extends AppContextService> |
getService(java.lang.Class<S> clazz) |
java.util.Collection<AppContextService> |
getServices()
Return a collection of the current
AppContextService s
This is used for generating debugging info. |
java.lang.String |
getTaggedProperty(java.lang.String name,
java.lang.String tag)
Query a property with generic and specialised forms.
|
boolean |
hasAttribute(java.lang.Object key)
Do we have the specified attribute set
|
<T extends Contexed> |
makeContexedObject(java.lang.Class<T> clazz)
Construct an object that implements Contexed using the non-tagged constructor
(if it exists).
|
<T> T |
makeObject(java.lang.Class<T> clazz)
Create an instance from a class.
|
<T> T |
makeObject(java.lang.Class<T> clazz,
java.lang.String tag)
Construct an object identified by a string tag.
|
<T> T |
makeObjectWithDefault(java.lang.Class<T> clazz,
java.lang.Class<? extends T> default_class,
java.lang.String tag)
Construct an object identified by a string tag.
|
<T> T |
makeObjectWithDefault(java.lang.Class<T> clazz,
java.lang.Class<? extends T> default_class,
java.lang.String path,
java.lang.String name)
Construct an object identified by a string tag and an optional qualifier string.
|
<T> T |
makeParamObject(java.lang.Class<T> clazz,
java.lang.Object... param)
Construct an object based on a supplied parameter list.
|
static boolean |
parseBooleanParam(java.lang.String parm,
boolean def) |
void |
removeAttribute(java.lang.Object key)
remove an object cached in the AppContext
|
void |
removeCached(java.lang.String path,
java.lang.String tag) |
void |
setAttribute(java.lang.Object key,
java.lang.Object value)
method for caching an object in the AppContext Code should never assume
the existance of an attribute this should only be used for short term
caching to avoid unecessary database queries.
|
<S extends AppContextService> |
setService(S service) |
public static final java.lang.String CLASSDEF_PROP_PREFIX
public static final Feature CONTEXT_CACHE_FEATURE
public static final Feature DATABASE_FEATURE
public static final Feature TAG_CHECK_FEATURE
public static final java.lang.String CLASS_PREFIX
public AppContext()
public AppContext(java.util.Properties props)
public void close()
AppContext
The AppContextCleanup.cleanup()
method is called on
each service in the reverse order that services were created.public void error(java.lang.Throwable e, java.lang.String text)
e
- Exception generating error.text
- Text of error.public final void error(java.lang.String errors)
errors
- Text of error.public final java.lang.Object getAttribute(java.lang.Object key)
We use Object as the key instead of String so that classes can create private key objects (e.g. an Enum) to ensure cached objects are not accessible outside the class.
key
- public boolean hasAttribute(java.lang.Object key)
key
- public java.util.Map<java.lang.Object,java.lang.Object> getAttributes()
public final <S extends AppContextService> S getService(java.lang.Class<S> clazz)
public final java.util.Collection<AppContextService> getServices()
AppContextService
s
This is used for generating debugging info.public <S extends AppContextService<S>> void clearService(java.lang.Class<S> clazz)
public <S extends AppContextService> S setService(S service)
public boolean getBooleanParameter(java.lang.String name, boolean def)
name
- String name of paameterdef
- boolean default if it does not exist.public static boolean parseBooleanParam(java.lang.String parm, boolean def)
public double getDoubleParam(java.lang.String name, double def)
public final java.lang.String getInitParameter(java.lang.String name)
name
- Name of parameterpublic final java.lang.String getExpandedProperty(java.lang.String name)
public final java.lang.String getExpandedProperty(java.lang.String name, java.lang.String def)
public java.lang.String expandText(java.lang.String text_to_expand)
text_to_expand
- public final java.lang.String getTaggedProperty(java.lang.String name, java.lang.String tag)
name
- base property nametag
- specialisationpublic final java.lang.String getInitParameter(java.lang.String name, java.lang.String fallback)
name
- Name of parameterfallback
- Default valuepublic final <E extends java.lang.Enum> E getEnumParameter(java.lang.Class<E> clazz, java.lang.String name, E fallback)
public final java.util.Hashtable<java.lang.String,java.lang.String> getInitParameters(java.lang.String prefix)
prefix
- Stringpublic int getIntegerParameter(java.lang.String name, int def)
public long getLongParameter(java.lang.String name, long def)
public java.util.Properties getProperties()
public <T extends Contexed> T makeContexedObject(java.lang.Class<T> clazz) throws java.lang.Exception
T
- clazz
- java.lang.Exception
public <T extends Contexed> boolean canMakeContexedObject(java.lang.Class<T> clazz)
canMakeContexedObject(Class)
clazz
- public <T> T makeObject(java.lang.Class<T> clazz) throws java.lang.Exception
T
- type to produceclazz
- Class of type to createjava.lang.Exception
Contexed
public <T> boolean canMakeObject(java.lang.Class<T> clazz)
makeObject(Class)
clazz
- public <T> T makeParamObject(java.lang.Class<T> clazz, java.lang.Object... param) throws java.lang.Exception
T
- clazz
- Class of object to makeparam
- parameter listjava.lang.Exception
public <T> java.lang.reflect.Constructor<T> findConstructor(java.lang.Class<T> clazz, java.lang.Object... param)
T
- clazz
- param
- public <T> java.lang.reflect.Constructor<T> findConstructorFromParamSignature(java.lang.Class<T> clazz, java.lang.Class... param)
T
- clazz
- param
- array of class types from parameterpublic final <T> T makeObject(java.lang.Class<T> clazz, java.lang.String tag)
T
- return typeclazz
- default super classtag
- public final <T> T makeObjectWithDefault(java.lang.Class<T> clazz, java.lang.Class<? extends T> default_class, java.lang.String tag)
T
- return typeclazz
- return type classdefault_class
- tag
- public final <T> T makeObjectWithDefault(java.lang.Class<T> clazz, java.lang.Class<? extends T> default_class, java.lang.String path, java.lang.String name)
The qualifier string if for cases where it is convenient to use the same tag string for various related classes.
The exact class to construct can be set using the property class.path.tag Or (if path is null or the property is not set) class.tag If neither property is not set then the default_class is constructed. If the default class cannot be instantiated null is returned. It is quite common to need to parameterise the constructed class using the tag. We therefore look for a string parameterised constructor in preference. If such a constructor is found.
T
- return typeclazz
- return type classdefault_class
- path
- name
- public <T> java.lang.Class<? extends T> getPropertyClass(java.lang.Class<T> template, java.lang.String tag)
T
- type that the target class must extend or implementtemplate
- Class object for Ttag
- public final <T> java.lang.Class<? extends T> getPropertyClass(java.lang.Class<T> template, java.lang.Class<? extends T> default_class, java.lang.String tag)
The use of classdef parameters is preferred as it makes it easier to provide backwards compatibility when classes are renamed. It also allows
T
- type that the target class must extend or implementtemplate
- Class object for Tdefault_class
- Class to use if no property settag
- public java.util.List<java.lang.Class> getClassList(java.lang.Class template, java.lang.String name)
public <T> java.util.Map<java.lang.String,java.lang.Class> getClassMap(java.lang.Class<T> template)
Composable
Composite
of) a target type
This will only find classes registered with the config service.T
- type being looked for.template
- Class of target.public <T> java.lang.Class<? extends T> getClassFromName(java.lang.Class<T> template, java.lang.Class<? extends T> default_class, java.lang.String tag)
ClassCastException
will be thrown if
a definition incompatible with the template is found. Without a default_class null is returned in both cases.
Note this can take fully qualified class names so it is safer not to allow the
class_name to be set from untrusted content. Instead use getPropertyClass(java.lang.Class<T>, java.lang.String)
which ensures only classes registered with the ConfigService
can be generated.T
- template
- default_class
- result to use if no definitiontag
- Either a fully qualified class name or a classdef tag.public <T> java.lang.Class<? extends T> getClassDef(java.lang.Class<T> template, java.lang.String name)
public final void removeAttribute(java.lang.Object key)
key
- public final void setAttribute(java.lang.Object key, java.lang.Object value)
We use Object as the key instead of String so that classes can create private key objects (e.g. an Enum) to ensure cached objects are not accessible outside the class.
key
- used to identify attributevalue
- Object to be stored.public final void clearAttributes()
public final void removeCached(java.lang.String path, java.lang.String tag)