More Flexible Sakai Configuration
Using sakai-configuration.xml to configure Sakai
1. Background
In Sakai 2.5.x and earlier versions, the only standard way to configure the Sakai framework and application suite is through a set of optional properties files placed in the installation's "sakai.home" (and possibly "sakai.security") areas:
${sakai.home}sakai.properties
- For most changes to text properties${sakai.home}local.properties
- Meant for text properties that are specific to a single machine on a cluster${sakai.security}security.properties
- Meant for text properties that require tighter access permissions than those of "sakai.home"${sakai.home}placeholder.properties
- Deprecated file, still checked to support legacy installations
Other integration and customization needs could only be met by discarding the binary distribution, editing the source code, and re-building.
2. sakai-configuration.xml
As of 2.6, Sakai will also check your "sakai.home" area for a Spring bean definition file named "sakai-configuration.xml"
. This file will be read after all Sakai component definitions have been loaded, but before the system starts. It can be used for the following purposes (in ascending level of risk):
- To customize the list of properties files
- To handle configurations that are too complex for a single string property
- To override or disable standard service implementations
2.1. Examples of customizing beans
2.1.1. Customizing the list of properties files
Let's say your institution maintains three server clusters, one for development, one for QA, and one for production. The three deployments use different database tables, and each machine in a cluster needs to set its own "serverId" property, but otherwise it's important that they share the same configuration. The following sakai-configuration.xml
file might serve your needs well:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <!-- Change the list of local properties files. --> <bean id="org.sakaiproject.component.SakaiProperties" parent="org.sakaiproject.component.DefaultSakaiProperties"> <property name="locations"> <list merge="true"> <value>file:${sakai.home}standard.properties</value> <value>file:${sakai.home}database.properties</value> <value>file:${sakai.home}server.properties</value> </list> </property> </bean> </beans>
For more background, see - SAK-8315Getting issue details... STATUS .
2.1.2. Customizing gradebook values
Let's say you just wanted to change the grading scales in edu-services. The default bean listed in the components.xml isn't in shared and has some properties not worth overriding anyway, but you can override the importantvalues. The below just overrides to only have A's and B's. You can add as many GradingScaleDefinition beans as you like just like in the original file. This sakai-configuration.xml
file might serve your needs well:
Note - SAK-29740Getting issue details... STATUS changed the defaultBottomPercents. You either need to set DefaultBottomPercents as a map or use the defaultBottomPercentsAsList as in the example.
<map>
<entry key="P" value="75.0" />
<entry key="NP" value="0.0" />
</map>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <!-- Simple configuration handler. --> <bean id="org_sakaiproject_service_gradebook_GradebookScalesConfiguration" class="org.sakaiproject.service.gradebook.shared.GradebookConfiguration" init-method="init"> <!-- Set up default system-wide grading scales. --> <property name="gradebookFrameworkService" ref="org.sakaiproject.service.gradebook.GradebookFrameworkService"/> <property name="availableGradingScales"> <list> <bean class="org.sakaiproject.service.gradebook.shared.GradingScaleDefinition"> <property name="uid" value="LetterGradePlusMinusMapping"/> <property name="name" value="Letter Grades with +/-"/> <property name="grades"> <list> <value>A</value> <value>A-</value> <value>B+</value> <value>B</value> </list> </property> <property name="defaultBottomPercentsAsList"> <list> <value>95.0</value> <value>90.0</value> <value>87.0</value> <value>83.0</value> </list> </property> <property name="defaultGradingScale" value="LetterGradePlusMinusMapping"/> </bean> </beans>
2.1.3. Switching from DBCP to the tomcat pool
In Sakai 10 support was added to make it easier to switch the BaseDataSource bean over to the tomcat one (from the default DBCP one). You just need to override this bean in this file. - KNL-1000Getting issue details... STATUS
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <!-- Shared DataSource for all pooled database connections --> <!-- Either make this javax.sql.dbcp.BaseDataSource or javax.sql.tomcat.BaseDataSource --> <bean id="javax.sql.BaseDataSource" parent="javax.sql.tomcat.BaseDataSource"></bean> </beans>
2.2. Complex configuration
Some sorts of configuration are too complex to be handled by overriding a text property. One example is defining how LDAP attributes or enrollment statuses should map to Sakai user roles.
If a service's API includes an externalizable configuration object, sakai-configuration.xml
can be used to override that configuration's default settings.
For example, let's say your institution uses the standard Course-Management-based site role provider, but needs to customize the default role mappings to match the enrollment data available from your student information systems. For the Sakai 2.6 CourseManagementGroupProvider, here's a sample customization:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd"> <!-- Customize mapping from Course Management data to Sakai roles --> <util:map id="org.sakaiproject.coursemanagement.GroupProviderConfiguration"> <entry key="siteRoleResolutionOrder"> <list> <value>Instructor</value> <value>Student</value> </list> </entry> <entry key="officialInstructorToSiteRole" value="Instructor"/> <entry key="enrollmentStatusToSiteRole"> <map> <entry key="E" value="Student"/> <entry key="W" value="Student"/> </map> </entry> <entry key="sectionRoleToSiteRole"> <map> <entry key="teacher" value="Instructor"/> <entry key="learner" value="Student"/> </map> </entry> </util:map> </beans>
CAUTION
This is a new capability in Sakai 2.6, and few service APIs have changed to take advantage of it. In many cases, if you mistakenly try to use this feature to override a service-internal object, Sakai will simply fail due to classloader issues. In some cases, however, you might succeed in overriding an object that's not part of a service's supported API, which would leave your installation open to unexpected breakage in later releases of Sakai.
Note that a similar caution applies to sakai.properties
lines which override bean properties using the "@" syntax:
internalUseOnly@org.sakaiproject.some.ClassNotInterface=kablooey
For more background, see - SAK-12237Getting issue details... STATUS .
2.3. Disabling standard service implementations
A Sakai binary release deploys many components, including some that were designed with installation-specific overrides in mind, and possibly also including some not-so-customizable services that you find you need to replace or disable.
To better support planned overrides, over time the product suite has begun using standard Spring techniques such as lazy loading, proxies, and injection-by-reference. As a result, in Sakai 2.6 you're able to enable your own user directory provider, your own course management service, and your own group-authorization provider through a Sakai properties file rather than having to comment out or delete released source code.
Unplanned overrides are a different story. Should you find yourself in such a position, it may be possible to disable or replace a standardly deployed Sakai component without taking on the extra maintenance cost of an edited source tree. Because sakai-properties.xml
takes effect after all component definitions have been read, if the file includes a bean alias or overrides a bean definition, the original component definition will effectively be lost.
For example, if you're developing a reimplementation of Sakai's Section Awareness Service, you might want to swap a test system back and forth between your experimental prototype and the official code. This sakai-configuration.xml
might work for you:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <!-- Override standard service implementation --> <alias name="edu.myschool.ExperimentalSectionAwareness" alias="org.sakaiproject.section.api.SectionAwareness"/> </beans>
WARNING
Unless otherwise documented, this technique should be treated as highly dangerous. It's possible that non-lazily-loaded beans will expect to find the exact service you've written over, or that you've accidentally broken other internal dependencies. Even if the override appears to work for a particular version of Sakai, there's no guarantee that it will continue to work with the next minor maintenance release.
To put it another way, this approach eliminates the cost of maintaining and building source code for a local branch, but it will not eliminate the QA cost associated with local branches. Even though you haven't modified the Java or XML files included in a Sakai release, you must view this as an unsupported modification of Sakai's runtime behavior.
3. Bean Overrides
If you wish to create new beans inside a component then you can define additional these additional beans in a set of files defined in "sakai.home"/override/{component-name}.xml when the component manager is starting up it will look in there and load an additional beans defined in this file. This allows you to define new spring beans.
If you want to configure Sakai to use LDAP you can copy /providers/component/src/webapp/WEB-INF/jldap-beans.xml to "sakai.home"/override/sakai-component-pack.xml and edit the file for point at your local LDAP server and anything else you need to set.
4. Alternatives and future directions
- Dynamic configuration approaches - Some subset of Sakai properties can safely be changed on a running system. Also, some installations might prefer to avoid dealing directly with a text file when configuring Sakai properties. Tony Atkins of U. Highlands and Islands has created a Configuration Viewer and Editor application, and Thomas Amsler of U. California, Davis, has created a Dynamic Configuration Service which can be administered with JMX.
- Centralized control of deployed components - Support for easier enabling and disabling of Sakai services and applications has long been requested. As the Sakai project suite continues to expand, the need only becomes more imperative. It's likely that the Component Manager will be redesigned for the next major version of Sakai, with this among the requirements.