Obsolete Pages{{Obsolete}}
The official documentation is at: http://docs.alfresco.com
In Alfresco terminology, a subsystem is a configurable module responsible for a sub-part of Alfresco functionality. Typically, a subsystem wraps an optional functional area such as IMAP binding, or one with several alternative implementations, such as authentication.
A subsystem can be thought of as miniature Alfresco server embedded within the main one, in that
This Application Context is a 'child' of the main one, meaning that it can reference all the beans in the main application context. However, the subsystem's beans cannot be seen by the main application context and communication with the subsystem must be through explicitly imported interfaces. This means that subsystems:
As of Alfresco version 3.2, the subsystems are:
Generally, the prepackaged subsystem configuration files described below should not be edited (except when developing your own subsystem or contributing enhancements). Essentially they are parameterized template configuration that forms part of the core product. Alfresco and its contributors reserve the right to maintain these files and replace them with new versions in product patches and upgrades, so they are definitely not the place to put your own configuration. See #Configuring Subsystems for how to configure a subsystem for your own needs.
Every subsystem has a category and a type.
A subsystem's prepackaged configuration files should live under
alfresco/subsystems/<category>/<type>
in the classpath. In reality this means they will be under WEB-INF/classes/alfresco/subsystems in alfresco.war. Configuration for subsystems in the Repository project can currently be found here in SVN (although we may eventually decide to move the subsystems into their own project).
A subsystem's directory should contain one or more Spring XML bean definition metadata files with names matching the following pattern:
*-context.xml
These files will be loaded by the child application context that belongs to the subsystem instance.
The XML bean definitions may contain placeholders for properties that correspond to configuration parameters of the subsystem. As per standard Spring conventions, these placeholders begin with ${ and end with }. For example, in the following example the value of the ooo.user configuration parameter will be substituted into the bean definition when it is loaded.
<bean id='userInstallationURI' class='org.alfresco.util.OpenOfficeURI'>
<constructor-arg>
<value>${ooo.user}</value>
</constructor-arg>
</bean>
Note that there is no need to declare a PropertyPlaceholderConfigurer bean. An appropriate one is added into the application context automatically.
A subsystem should declare default values for all the properties it requires in one or more .properties files in its subsystem directory. So in this example we might have a mysubsystem.properties file containing
ooo.user=${dir.root}/oouser
Note that it is perfectly legal to include placeholders for system-wide properties such as dir.root in the -context.xml and .properties file, as the child application context will recursively expand placeholders for its own properties and all the placeholders recognized by its parent.
Note the properties files in the subsystem directory just declare the existence of configuration parameters and provide default values where these have not been supplied elsewhere. These files should not be edited in order to configure the subsystem. Read #Configuring Subsystems to find out how to configure a prepackaged subsystem.
Despite how painful this might sound, a subsystem can be mounted quite easily, that is, its existence can be declared to the main server, through the ChildApplicationContextFactory bean. This is an object that wraps the Spring Application Context that owns the subsystem and its beans. It initializes its application context as a child of the main Alfresco context with an appropriate PropertyPlaceholderConfigurer that will expand its configuration parameters.
Note that any instances you define should extend the abstractPropertyBackedBean definition. The ID you define for the bean automatically becomes the subsystem's category and hence defines where the factory will look for configuration files, in the search paths described above.
For example, in the core bootstrap-context.xml file (the file that controls the startup of beans and their order), we have
<bean id='thirdparty' class='org.alfresco.repo.management.subsystems.ChildApplicationContextFactory' parent='abstractPropertyBackedBean'>
<property name='autoStart'>
<value>true</value>
</property>
</bean>
The autoStart property has been set to true, meaning that the child application context will be refreshed when the server boots up, thus activating the beans it contains. For subsystems containing background processes or daemons (e.g. the file server subsystem) it is very important to set this property, because nothing else will ever cause the subsystem to 'wake up'.
It may have dawned on you that, because a subsystem is limited to flat property sets for its configuration, it would be rather difficult to allow structured data in this configuration. This is where the concept of composite properties comes in.
A composite property is a special property whose value is a list of beans.
For example, the IMAP subsystem is mounted thus:
<bean id='imap' class='org.alfresco.repo.management.subsystems.ChildApplicationContextFactory' parent='abstractPropertyBackedBean'>
<property name='autoStart'>
<value>true</value>
</property>
<property name='compositePropertyTypes'>
<map>
<entry key='imap.config.server.mountPoints'>
<value>org.alfresco.repo.imap.config.ImapConfigMountPointsBean</value>
</entry>
</map>
</property>
</bean>
The above subsystem declares a single composite property called imap.config.server.mountPoints with component type org.alfresco.repo.imap.config.ImapConfigMountPointsBean.
The configured value of this composite property is actually materialized in the child application context as a ListFactoryBean. The bean's ID should match the name of the composite property. So for example, in our IMAP subsystem configuration we have the following.
<bean id='imap.config.server.mountPoints' class='org.springframework.beans.factory.config.ListFactoryBean'>
<property name='sourceList'>
<list>
<bean id='Repository_virtual' class='org.alfresco.repo.imap.config.ImapConfigMountPointsBean'>
<property name='mode'>
<value>virtual</value>
</property>
<property name='store'>
<value>${spaces.store}</value>
</property>
<property name='path'>
<value>/${spaces.company_home.childname}</value>
</property>
</bean>
<bean id='Repository_archive' class='org.alfresco.repo.imap.config.ImapConfigMountPointsBean'>
<property name='mode'>
<value>archive</value>
</property>
<property name='store'>
<value>${spaces.store}</value>
</property>
<property name='path'>
<value>/${spaces.company_home.childname}</value>
</property>
</bean>
</list>
</property>
</bean>
Other beans in the subsystem application context can use imap.config.server.mountPoints as though it were a regular list of ImapConfigMountPointsBeans (which indeed it is!).
See the later sections for how to configure values for a composite property.
The other way of causing a subsystem to start up (if it hasn't already) is to actually programmatically call one of its interfaces.
The only way to call into a subsystem programmatically from outside (e.g. in the main server or a different subsystem) is to 'import' one or more of its interfaces into the main application context. This is done by using SubsystemProxyFactory to create a dynamic proxy that proxies one or more of the subsystem's interfaces to the main application context.
For example, in swf-transform-context.xml we have:
<bean id='transformer.worker.Pdf2swf' class='org.alfresco.repo.management.subsystems.SubsystemProxyFactory'>
<property name='sourceApplicationContextFactory'>
<ref bean='thirdparty' />
</property>
<property name='sourceBeanName'>
<value>transformer.worker.Pdf2swf</value>
</property>
<property name='interfaces'>
<list>
<value>org.alfresco.repo.content.transform.ContentTransformerWorker</value>
</list>
</property>
</bean>
You can see how it ties the ContentTransformerWorker interface to the thirdparty subsystem. In this specific case, it also names the specific bean that the proxy should target, because there may be multiple instances of ContentTransformerWorker in the child application context. If there were only one singleton ContentTransformerWorker in the child application context, it would not be necessary to name the bean, and it would be found automatically by its interface.
You should be very careful about which interfaces you choose to import in this way, as they effectively define the public interface of your subsystem. The more interfaces you mount, the more tightly coupled you become to the subsystem and the less easier it becomes to replace it with an alternative implementation. Try to make sure you do not mount interfaces that expose any internal implementation details of your subsystem.
As explained above, one of the strengths of subsystems is that they do not require you to edit or override core Spring configuration in order to configure Alfresco to meet your needs. You simply have to bind suitable values to the subsystem's properties. Depending on the version you are using, there are several options open to you for doing this.
In Alfresco Enterprise versions, your subsystems and all their composite properties will show up under the Alfresco:Type=Configuration tree in JConsole. When you edit a property the subsystem is stopped automatically. You can then continue to edit further properties. All property edits are persisted in the database and will be remembered on server restarts and synchronized across your cluster. Once you have finished editing properties and want to try out your changes, you can start the subsystem by calling its start operation. This allows complex configuration to be built up without endless server restarts.
Below is an example of the default authentication objects:
** objectName: Alfresco:Type=Configuration,Category=Authentication,id1=manager
++ ClassName: Authentication$manager
chain: alfrescoNtlm1:alfrescoNtlm
** objectName: Alfresco:Type=Configuration,Category=Authentication,id1=managed,id2=alfrescoNtlm1
++ ClassName: Authentication$managed$alfrescoNtlm1
$type: alfrescoNtlm
alfresco.authentication.allowGuestLogin: true
alfresco.authentication.authenticateCIFS: true
ntlm.authentication.mapUnknownUserToGuest: false
ntlm.authentication.sso.enabled: false
Note that the persisted data in the database takes precedence over the data in the properties files. So if you consider an authentication chain 'authentication.chain=ldap1:ldap
', even if you have in
shared/classes/alfresco-global.properties
or in
shared/classes/alfresco/extension/subsystems/Authentication/ldap/ldap1/ldap-authentication.properties
a line:
ldap.synchronization.active=true
this will not be taken into account as the value in SQL take precedence.
Overall defaults for subsystem properties are set in this file, and in community editions it is your best option for configuring single-instance subsystems. Simply add the property you want to set to this file and restart your server. Refer to Repository_Configuration#Global_Property_Overrides for more information on alfresco-global.properties.
Recall the imap.config.server.mountPoints property we defined above. The ImapConfigMountPointsBean class that holds the component beans has four properties of its own:
Firstly, suppose we want to set some overall defaults for all component instances. These values would show up, for example when you added a new component instance but did not specify its properties. We use the format
<property>.default.<component property>
to specify default values for each component property. For example:
imap.config.server.mountPoints.default.store=${spaces.store}
imap.config.server.mountPoints.default.rootPath=/${spaces.company_home.childname}
imap.config.server.mountPoints.default.mode=virtual
We did not define a default for beanName because we have a special way of populating that for each instance, as we will explain soon. Now suppose we want to set up the imap.config.server.mountPoints with an actual composite value.
First, we set the master composite property using a comma-separated list
imap.config.server.mountPoints=Repository_virtual,Repository_archive
This defines that the property contains two ImapConfigMountPointsBean instances, named Repository_virtual and Repository_archive. Because ImapConfigMountPointsBean implements the BeanNameAware Spring interface and has a beanName property, these instance names are automatically set as the bean names. If we did nothing further, we would end up with two component instances with bean names set and the other default component property values defined above. But how do we define component properties specific to each component instance?
We use the format
<property>.value.<component instance name>.<component property>
So in this case, we set
imap.config.server.mountPoints.value.Repository_virtual.mode=virtual
imap.config.server.mountPoints.value.Repository_archive.mode=archive
As its name suggests, alfresco-global.properties can only be used to define properties that are global to the whole system. So how do we control the properties of subsystems that can have multiple instances, e.g. the Authentication subsystems? We need to be able to target different values for the same properties to each subsystem instance. This is where the special extension classpath mechanism comes in handy.
If you add a property file to your application server's global classpath (e.g. under $TOMCAT_HOME/shared/classes) with a path matching the following pattern you can override specific properties of a subsystem instance.
alfresco/extension/subsystems/<category>/<type>/<id>/*.properties
Here, the ID is the subsystem instance identifier, which will be default for single instance subsystems, or the provided ID for chained subsystems.
So, for example, suppose your authentication chain looked like this:
authentication.chain=alfrescoNtlm1:alfrescoNtlm,ldap1:ldap
Then you could put property overrides for alfrescoNtlm1 in
alfresco/extension/subsystems/Authentication/alfrescoNtlm/alfrescoNtlm1/mychanges.properties
Remembering that the default type and ID of non-chained subsystems is default you could put overrides for file server properties in
alfresco/extension/subsystems/fileServers/default/default/mychanges.properties
OutboundSMTP and InboundSMTP are unusual subsystems in that they declare their own <type> and <id>. The correct paths for these subsystems are
alfresco/extension/subsystems/email/OutboundSMTP/outbound/mychanges.properties
and
alfresco/extension/subsystems/email/InboundSMTP/inbound/mychanges.properties
Below, we show how the properties displayed in JMX relates to the path rule. The path rule:
alfresco/extension/subsystems/<category>/<type>/<id>/*.properties
translates for the JMX object:
** objectName: Alfresco:Type=Configuration,Category=Authentication,id1=managed,id2=alfrescoNtlm1
++ ClassName: Authentication$managed$alfrescoNtlm1
$type: alfrescoNtlm
alfresco.authentication.allowGuestLogin: true
alfresco.authentication.authenticateCIFS: true
ntlm.authentication.mapUnknownUserToGuest: false
ntlm.authentication.sso.enabled: false
into:
alfresco/extension/subsystems/Authentication/alfrescoNtlm/alfrescoNtlm1/mychanges.properties
For advanced purposes, you can also extend or override the Spring Bean definitions of the subsystem.
If you add a Spring Bean file to your application server's global classpath (e.g. under $TOMCAT_HOME/shared/classes) with a path matching the following pattern you can add to or override the subsystem bean definitions.
alfresco/extension/subsystems/<category>/<type>/<id>/*-context.xml
Here, the ID is the subsystem instance identifier, which will be default for single instance subsystems, or the provided ID for chained subsystems.
So, for example, suppose your authentication chain looked like this:
authentication.chain=alfrescoNtlm1:alfrescoNtlm,ldap1:ldap
Then you could put bean definition overrides for alfrescoNtlm1 in
alfresco/extension/subsystems/Authentication/alfrescoNtlm/alfrescoNtlm1/custom-context.xml
Remembering that the default type and ID of non-chained subsystems is default you could put overrides for file server beans in
alfresco/extension/subsystems/fileServers/default/default/custom-file-servers-context.xml
Here are some 4.0 examples for SOLR and Lucene subsystems
shared/classes/alfresco/extension/subsystems/Search/solr/solr/custom-solr-context.xml
shared/classes/alfresco/extension/subsystems/Search/lucene/lucene/custom-lucene-context.xml
As shown above, configuration changes can be made using
In any case, the JMX interface holds the current values of a running system. So when talking to Support, it can be handy to make a dump of your JMX settings.
A JMX dumper is available on network (see file jmx-dumper-3.2.0.jar)
It can be run using:
java -jar jmx-dumper-3.2.0.jar > envLog.log
The usage of the jar can be found using the --help option.
java -jar jmx-dumper.jar --help
Usage: java -jar jmx-dumper.jar [-u userName] [-p password] [URL]*
If no URL is specified, will attempt to locate local Alfresco processes
If no user name or password is specified, will use Alfresco defaults
Example: java -jar jmx-dumper.jar -u controlRole -p change_asap service:jmx:rmi://localhost/jndi/rmi://localhost:50500/alfresco/jmxrmi
Another (simpler) option is to use the web JMX dumper that can be accessed as 'admin' at the URL:
http://localhost:8080/alfresco/faces/jsp/admin/jmx-dumper.jsp
At this address you get the same information as running the JAR dumper.
As discussed above, the precedence for the configuration properties files for subsystems are :
JMX changes persisted in the database
>> precedes >>
attribute changes made in a specific subsystem
* shared/classes/alfresco/extension/subsystems/<category>/<type>/<id>
>> precedes >>
attribute changes made in the default subsystem
* shared/classes/alfresco/extension/subsystems/<category>/default/default
>> precedes >>
attribute changes made in the global.properties
* shared/classes/alfresco-global.properties
>> precedes >>
default attribute values set in:
* webapps/alfresco/WEB-INF/classes/alfresco/subsystems/<category>/<type>/<id>