Close

Bootstrap Content Extension Point

For many content management solutions it is useful to have some data populated when the solution is first deployed. This is done by bootstrapping content.

Architecture Information: Platform Architecture

Description

When implementing a content management solution it is common to have some content, such as sites, that is part of the solution. To load this content into the repository when the solution is first deployed we use bootstrapping. To bootstrap content means to load it once into the repository. Besides bootstrapping sites, it is also common to bootstrap folders, files, categories, rules, permissions, users, and groups. There are two ways in which content can be boostrapped (imported) into the repository via an AMP or JAR module extension. There is patch based bootstrapping that is triggered based on the Alfresco schema version and is not linked to the module version. Patch bootstrapping can, for example, be used for database schema upgrades. But it can also be used to bootstrap Share sites and other types of content. Then we have the importer module component that is used more often as the bootstrapping happens when the module (i.e. AMP or JAR) is deployed into the repository. The execution of the importer component is tied to a specific version of the module, which is handy when a module evolves incrementally.

Both the patch approach and the importer module component approach uses a specific XML format to describe what content that should be imported and where it should go in the repository. When you export content from the repository it will be descibed in this XML format. Exported content usually comes packaged in an Alfresco Content Package (ACP), which is just a ZIP file, and it contains this XML file plus the binary files for the content.

Important: If you mix patches and importer components when bootstrapping content it might not work in all situations as patches are executed before importer components. For example, if you have an importer component that bootstraps some groups that should later be used by a site load patch, it will not work.

The following sections will show the type of XML needed for importing different types of content and the associated Spring beans, in these samples we use the patch approach.

Let’s start bootstrapping some users and groups as they are usually used also when bootstrapping permissions and sites. Normally users and groups would be imported via a directory sync, but let’s just bootstrap them manually for demonstration purposes. Sometimes you also need special users that aren’t in the directory, such as test users.

Bootstrapping users

Bootstrapping users into the repository involves two steps, the first takes care of bootstrapping the User Profile with first name, last name, email etc. This is done with an XML file looking like this:

<?xml version="1.0" encoding="UTF-8"?>
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
           xmlns:cm="http://www.alfresco.org/model/content/1.0">
    <cm:person view:childName="cm:alftest1">
        <view:acl>
            <view:ace view:access="ALLOWED">
                <view:authority>alftest1</view:authority>
                <view:permission>All</view:permission>
            </view:ace>
        </view:acl>
        <view:properties>
            <cm:firstName>Alf Test</cm:firstName>
            <cm:lastName>Number 1</cm:lastName>
            <cm:email>alftest1@alfresco.com</cm:email>
            <cm:userName>alftest1</cm:userName>
            <cm:homeFolder>/app:company_home/app:user_homes/cm:alftest1</cm:homeFolder>
            <cm:organizationId>Alfresco</cm:organizationId>
            <cm:sizeQuota>-1</cm:sizeQuota>
            <cm:sizeCurrent>0</cm:sizeCurrent>
        </view:properties>
    </cm:person>
    <cm:person view:childName="cm:alftest2">
        <view:acl>
            <view:ace view:access="ALLOWED">
                <view:authority>alftest2</view:authority>
                <view:permission>All</view:permission>
            </view:ace>
        </view:acl>
        <view:properties>
            <cm:firstName>Alf Test</cm:firstName>
            <cm:lastName>Number 2</cm:lastName>
            <cm:email>alftest2@alfresco.com</cm:email>
            <cm:userName>alftest2</cm:userName>
            <cm:homeFolder>/app:company_home/app:user_homes/cm:alftest2</cm:homeFolder>
            <cm:organizationId>Alfresco</cm:organizationId>
            <cm:sizeQuota>-1</cm:sizeQuota>
            <cm:sizeCurrent>0</cm:sizeCurrent>
        </view:properties>
    </cm:person>
</view:view>

In this case we are bootstrapping profile information for two users, alftest1 and alftest2. We can store this XML file as part of the Repository JAR module extension project in a file name such as import-user-profiles.xml.

For each user profile we bootstrap, Content Services also needs some internal account information set up, such as password, account expire information etc. This is also done in an XML file as follows:

<?xml version="1.0" encoding="UTF-8"?>
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
           xmlns:usr="http://www.alfresco.org/model/user/1.0"
           xmlns:sys="http://www.alfresco.org/model/system/1.0">

    <!-- Load the user account information -->
    <usr:user view:childName="usr:alftest1">
        <view:aspects>
            <sys:referenceable></sys:referenceable>
        </view:aspects>
        <view:properties>
            <usr:username>alftest1</usr:username>
            <usr:password>7ce21f17c0aee7fb9ceba532d0546ad6</usr:password> <!-- 1234 -->
            <usr:accountExpires>false</usr:accountExpires>
            <usr:credentialsExpire>false</usr:credentialsExpire>
            <usr:accountLocked>false</usr:accountLocked>
            <usr:enabled>true</usr:enabled>
        </view:properties>
    </usr:user>
    <usr:user view:childName="usr:alftest2">
        <view:aspects>
            <sys:referenceable></sys:referenceable>
        </view:aspects>
        <view:properties>
            <usr:username>alftest2</usr:username>
            <usr:password>7ce21f17c0aee7fb9ceba532d0546ad6</usr:password> <!-- 1234 -->
            <usr:accountExpires>false</usr:accountExpires>
            <usr:credentialsExpire>false</usr:credentialsExpire>
            <usr:accountLocked>false</usr:accountLocked>
            <usr:enabled>true</usr:enabled>
        </view:properties>
    </usr:user>
</view:view>

The password is stored as an MD4 Hash, which can be generated following the instructions on this page.

Note that while MD4 is the default encoding format for passwords, there is additional support for Bcrypt. For more information about Bcrypt support, see Cryptographic password hashing.

We can store this XML file as part of the Repository JAR module extension project in a file name such as import-users.xml.

These two XML files can be loaded via Spring bean configurations as follows:

<bean id="org.alfresco.tutorial.bootstrap.patch.userProfilesLoader"
      class="org.alfresco.repo.admin.patch.impl.GenericBootstrapPatch"
      parent="basePatch" >
    <property name="id"><value>org.alfresco.tutorial.bootstrap.patch.userProfilesLoader</value></property>
    <property name="description"><value>org.alfresco.tutorial.bootstrap.patch.userProfilesLoader.description</value></property>
    <property name="fixesFromSchema"><value>0</value></property>
    <property name="fixesToSchema"><value>${version.schema}</value></property>
    <property name="targetSchema"><value>99999</value></property>
    <property name="importerBootstrap">
        <ref bean="spacesBootstrap" />
    </property>
    <property name="bootstrapView">
        <props>
            <prop key="path">/${system.system_container.childname}/${system.people_container.childname}</prop>
            <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/import-user-profiles.xml</prop>
        </props>
    </property>
</bean>

<bean id="org.alfresco.tutorial.bootstrap.patch.usersLoader"
      class="org.alfresco.repo.admin.patch.impl.GenericBootstrapPatch"
      parent="basePatch" >
    <property name="id"><value>org.alfresco.tutorial.bootstrap.patch.usersLoader</value></property>
    <property name="description"><value>org.alfresco.tutorial.bootstrap.patch.usersLoader.description</value></property>
    <property name="fixesFromSchema"><value>0</value></property>
    <property name="fixesToSchema"><value>${version.schema}</value></property>
    <property name="targetSchema"><value>99999</value></property>
    <property name="dependsOn" >
        <list>
            <ref bean="org.alfresco.tutorial.bootstrap.patch.userProfilesLoader" />
        </list>
    </property>
    <property name="importerBootstrap">
        <ref bean="userBootstrap" />
    </property>
    <property name="bootstrapView">
        <props>
            <prop key="path">/${alfresco_user_store.system_container.childname}/${alfresco_user_store.user_container.childname}</prop>
            <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/import-users.xml</prop>
        </props>
    </property>
</bean>

Note how the user profile needs to be bootstrapped first. This is enforced with the dependsOn definition above.

The id and description properties should be specified in a message resource file as follows:

org.alfresco.tutorial.bootstrap.patch.usersLoader=Load Users
org.alfresco.tutorial.bootstrap.patch.usersLoader.description=Bootstraps users alftest1 and alftest2
org.alfresco.tutorial.bootstrap.patch.userProfilesLoader=Load User Profiles
org.alfresco.tutorial.bootstrap.patch.userProfilesLoader.description=Bootstraps first name, last name, email etc for user alftest1 and alftest2

Bootstrapping groups

This is also done via XML files:

<?xml version="1.0" encoding="UTF-8"?>
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
           xmlns:cm="http://www.alfresco.org/model/content/1.0"
           xmlns:sys="http://www.alfresco.org/model/system/1.0">

    <view:reference view:pathref="${system.authorities_container.childname}">
        <view:associations>
            <sys:children>
                <cm:authorityContainer view:childName="cm:GROUP_Knowledge Base Consumers">
                    <view:aspects>
                        <sys:referenceable />
                    </view:aspects>
                    <view:properties>
                        <sys:node-uuid>Knowledge Base Consumers</sys:node-uuid>
                        <cm:name>GROUP_Knowledge Base Consumers</cm:name>
                        <cm:authorityName>GROUP_Knowledge Base Consumers</cm:authorityName>
                    </view:properties>
                </cm:authorityContainer>
                <cm:authorityContainer view:childName="cm:GROUP_Knowledge Base Coordinators">
                    <view:aspects>
                        <sys:referenceable />
                    </view:aspects>
                    <view:properties>
                        <sys:node-uuid>Knowledge Base Coordinators</sys:node-uuid>
                        <cm:name>GROUP_Knowledge Base Coordinators</cm:name>
                        <cm:authorityName>GROUP_Knowledge Base Coordinators</cm:authorityName>
                    </view:properties>
                </cm:authorityContainer>
            </sys:children>
        </view:associations>
    </view:reference>

    <!-- Each group is also part of the AUTH.ALF and APP.DEFAULT zones -->
    <view:reference view:pathref="${system.zones_container.childname}/cm:AUTH.ALF">
        <view:associations>
            <cm:inZone>
                <view:reference view:pathref="${system.authorities_container.childname}/cm:GROUP_Knowledge_x0020_Base_x0020_Consumers"
                                view:childName="cm:GROUP_Knowledge Base Consumers" />
            </cm:inZone>
            <cm:inZone>
                <view:reference view:pathref="${system.authorities_container.childname}/cm:GROUP_Knowledge_x0020_Base_x0020_Coordinators"
                                view:childName="cm:GROUP_Knowledge Base Coordinators" />
            </cm:inZone>
        </view:associations>
    </view:reference>
    <view:reference view:pathref="${system.zones_container.childname}/cm:APP.DEFAULT">
        <view:associations>
            <cm:inZone>
                <view:reference view:pathref="${system.authorities_container.childname}/cm:GROUP_Knowledge_x0020_Base_x0020_Consumers"
                                view:childName="cm:GROUP_Knowledge Base Consumers" />
            </cm:inZone>
            <cm:inZone>
                <view:reference view:pathref="${system.authorities_container.childname}/cm:GROUP_Knowledge_x0020_Base_x0020_Coordinators"
                                view:childName="cm:GROUP_Knowledge Base Coordinators" />
            </cm:inZone>
        </view:associations>
    </view:reference>
</view:view>

Here we are bootstrapping two groups, one called Knowledge Base Consumers and one called Knowledge Base Coordinators. The last bit of the group bootstrapping adds the groups to different Zones. The AUTH.ALF zone is for authorities defined within Content Services and not synchronized from an external source, such as LDAP. The APP.DEFAULT zone is for person and group nodes to be found by a normal search. We can store this XML file as part of the Repository JAR module extension project in a file name such as import-groups.xml.

The group XML file can be loaded via a Spring bean configuration as follows:

<bean id="org.alfresco.tutorial.bootstrap.patch.groupsLoader"
      class="org.alfresco.repo.admin.patch.impl.GenericBootstrapPatch"
      parent="basePatch" >
    <property name="id"><value>org.alfresco.tutorial.bootstrap.patch.groupsLoader</value></property>
    <property name="description"><value>org.alfresco.tutorial.bootstrap.patch.groupsLoader.description</value></property>
    <property name="fixesFromSchema"><value>0</value></property>
    <property name="fixesToSchema"><value>${version.schema}</value></property>
    <property name="targetSchema"><value>99999</value></property>
    <property name="importerBootstrap">
        <ref bean="spacesBootstrap" />
    </property>
    <property name="bootstrapView">
        <props>
            <prop key="path">/${alfresco_user_store.system_container.childname}</prop>
            <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/import-groups.xml</prop>
        </props>
    </property>
</bean>

Adding users to groups

This is done via XML files:

<?xml version="1.0" encoding="UTF-8"?>
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
           xmlns:cm="http://www.alfresco.org/model/content/1.0">

    <view:reference view:pathref="${system.authorities_container.childname}/cm:GROUP_Knowledge_x0020_Base_x0020_Consumers">
        <view:associations>
            <cm:member>
                <view:reference view:pathref="${system.people_container.childname}/cm:admin"
                                view:childName="cm:admin" />
            </cm:member>
            <cm:member>
                <view:reference view:pathref="${system.people_container.childname}/cm:alftest1"
                                view:childName="cm:alftest1" />
            </cm:member>
        </view:associations>
    </view:reference>
    <view:reference view:pathref="${system.authorities_container.childname}/cm:GROUP_Knowledge_x0020_Base_x0020_Coordinators">
        <view:associations>
            <cm:member>
                <view:reference view:pathref="${system.people_container.childname}/cm:admin"
                                view:childName="cm:admin" />
            </cm:member>
            <cm:member>
                <view:reference view:pathref="${system.people_container.childname}/cm:alftest2"
                                view:childName="cm:alftest2" />
            </cm:member>
        </view:associations>
    </view:reference>
</view:view>

We add the admin user, which we get out-of-the-box, and the two users we bootstrapped previously. We can store this XML file as part of the Repository JAR module extension project in a file name such as import-group-memberships.xml.

The group membership XML file can be loaded via a Spring bean configuration as follows:

<bean id="org.alfresco.tutorial.bootstrap.patch.groupMembershipsLoader"
      class="org.alfresco.repo.admin.patch.impl.GenericBootstrapPatch"
      parent="basePatch" >
    <property name="id"><value>org.alfresco.tutorial.bootstrap.patch.groupMembershipsLoader</value></property>
    <property name="description"><value>org.alfresco.tutorial.bootstrap.patch.groupMembershipsLoader.description</value></property>
    <property name="fixesFromSchema"><value>0</value></property>
    <property name="fixesToSchema"><value>${version.schema}</value></property>
    <property name="targetSchema"><value>99999</value></property>
    <property name="dependsOn" >
        <list>
            <ref bean="org.alfresco.tutorial.bootstrap.patch.groupsLoader" />
            <ref bean="org.alfresco.tutorial.bootstrap.patch.userProfilesLoader" />
            <ref bean="org.alfresco.tutorial.bootstrap.patch.usersLoader" />
        </list>
    </property>
    <property name="importerBootstrap">
        <ref bean="spacesBootstrap" />
    </property>
    <property name="bootstrapView">
        <props>
            <prop key="path">/${system.system_container.childname}</prop>
            <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/import-group-memberships.xml</prop>
        </props>
    </property>
</bean>

Note how it depends on the beans that loads the users and groups.

The id and description properties for the group loading should be specified in a message resource file as follows:

org.alfresco.tutorial.bootstrap.patch.groupsLoader=Load Groups
org.alfresco.tutorial.bootstrap.patch.groupsLoader.description=Bootstraps groups KB Consumer and KB Coordinator
org.alfresco.tutorial.bootstrap.patch.groupMembershipsLoader=Load Group Memberships
org.alfresco.tutorial.bootstrap.patch.groupMembershipsLoader.description=Loads the groups KB Consumer and KB Coordinator with 2 users

Bootstrapping sites

We will now look at how to bootstrap a site. We can use some of the previously set up users and groups as members for demonstration purposes. First thing we need to do is create the site via Alfresco Share and then export it. We can export the site via the GET /alfresco/s/api/sites/{shortname}/export would use the http://localhost:8080/alfresco/s/api/sites/alfresco-kb/export URL. This will trigger an export of the site as a ZIP file with the following content:

  • Contents.acp (Contains all the content created for the site - set this up as bootstrapView “contents”)
  • Groups.txt (User/Group -> Site Group mapping - set this up as bootstrapView “groups”)
  • People.acp (Contains the User Profile XML - same bootstrap we did above with import-user-profiles.xml or set this up as bootstrapView “people”)
  • Users.acp (Contains the User User XML - same bootstrap we did above with import-user.xml or set this up as bootstrapView “users”)

We have already set up the users above so we need only the Contents.acp and Groups.txt files. We can then bootstrap the site with a special site load patch class as follows:

<bean id="org.alfresco.tutorial.bootstrap.patch.alfrescoKBsiteLoader"
      class="org.alfresco.repo.admin.patch.impl.SiteLoadPatch" parent="basePatch">
    <property name="id"><value>org.alfresco.tutorial.bootstrap.patch.alfrescoKBsiteLoader</value></property>
    <property name="description"><value>org.alfresco.tutorial.bootstrap.patch.alfrescoKBsiteLoader.description</value></property>
    <property name="fixesFromSchema"><value>0</value></property>
    <property name="fixesToSchema"><value>${version.schema}</value></property>
    <property name="targetSchema"><value>99999</value></property>
    <property name="dependsOn" >
        <list>
            <ref bean="org.alfresco.tutorial.bootstrap.patch.groupMembershipsLoader" />
        </list>
    </property>
    <property name="spacesBootstrap" ref="siteLoadBootstrap-Spaces"/>
    <property name="usersBootstrap" ref="siteLoadBootstrap-Users"/>
    <property name="siteService" ref="siteService"/>
    <property name="authorityService" ref="authorityService"/>
    <property name="behaviorFilter" ref="policyBehaviourFilter"/>
    <property name="siteName">
        <value>alfresco-kb</value>
    </property>
    <property name="bootstrapViews">
        <map>
            <entry key="contents">
                <props>
                    <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/alfresco-kb-site-contents.acp</prop>
                </props>
            </entry>
            <entry key="groups">
                <props>
                    <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/alfresco-kb-site-groups.txt</prop>
                </props>
            </entry>
        </map>
    </property>
</bean>

Note that the contents and groups files were renamed. The site load patch also depends on the groupMembershipsLoader so we can be sure that the users have been set up before this patch runs. If we don’t want to set up the users separately we can have the site load patch bootstrap everything like this:

<bean id="org.alfresco.tutorial.bootstrap.patch.alfrescoKBsiteLoader"
      class="org.alfresco.repo.admin.patch.impl.SiteLoadPatch" parent="basePatch">
        ...
        <property name="bootstrapViews">
        <map>
            <entry key="contents">
                <props>
                    <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/alfresco-kb-site-contents.acp</prop>
                </props>
            </entry>
            <entry key="groups">
                <props>
                    <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/alfresco-kb-site-groups.txt</prop>
                </props>
            </entry>
            <entry key="users">
                <props>
                    <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/Users.acp</prop>
                </props>
            </entry>
            <entry key="people">
                <props>
                    <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/Users.acp</prop>
                </props>
            </entry>
        </map>
    </property>
</bean>

The id and description properties for the site load patch should be specified in a message resource file as follows:

org.alfresco.tutorial.bootstrap.patch.groupMembershipsLoader.description=Loads the groups KB Consumer and KB Coordinator with 2 users
org.alfresco.tutorial.bootstrap.patch.alfrescoKBsiteLoader=Load Alfresco KB Site

Bootstrapping folders and files

Sometimes it is also necessary to bootstrap folders and files into locations outside sites. This can also be done with the generic bootstrap patch as follows:

<bean id="org.alfresco.tutorial.bootstrap.patch.foldersAndFilesLoader"
      class="org.alfresco.repo.admin.patch.impl.GenericBootstrapPatch"
      parent="basePatch" >
    <property name="id"><value>org.alfresco.tutorial.bootstrap.patch.foldersAndFilesLoader</value></property>
    <property name="description"><value>org.alfresco.tutorial.bootstrap.patch.foldersAndFilesLoader.description</value></property>
    <property name="fixesFromSchema"><value>0</value></property>
    <property name="fixesToSchema"><value>${version.schema}</value></property>
    <property name="targetSchema"><value>99999</value></property>
    <property name="importerBootstrap">
        <ref bean="spacesBootstrap" />
    </property>
    <!-- Can be used to check if something already exists, if it does then the patch will not be executed -->
    <property name="checkPath">
        <value>/${spaces.company_home.childname}/cm:acmedocument.txt</value>
    </property>
    <property name="bootstrapView">
        <props>
            <prop key="path">/${spaces.company_home.childname}</prop>
            <prop key="location">alfresco/module/bootstrap-content-repo/bootstrap/import-folders-and-files.xml</prop>
        </props>
    </property>
</bean>

The content of the import-folders-and-files.xml XML file has the same structure as the XML container in the Contents.acp we get when exporting a site. So to bootstrap a file it will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<view:view xmlns:cm="http://www.alfresco.org/model/content/1.0"
		   xmlns:view="http://www.alfresco.org/view/repository/1.0"
		   xmlns:sys="http://www.alfresco.org/model/system/1.0"
		   xmlns:app="http://www.alfresco.org/model/application/1.0"
		   xmlns:acme="http://www.acme.org/model/content/1.0">
<acme:document view:childName="cm:acmedocument.txt">
	<view:aspects>
		<cm:auditable></cm:auditable>
		<sys:referenceable></sys:referenceable>
		<cm:titled></cm:titled>
		<sys:localized></sys:localized>
		<app:inlineeditable></app:inlineeditable>
	</view:aspects>
	<view:acl></view:acl>
	<view:properties>
		<cm:name>acmedocument.txt</cm:name>
		<sys:node-dbid>854</sys:node-dbid>
		<sys:store-identifier>SpacesStore</sys:store-identifier>
		<sys:locale>en_GB_</sys:locale>
		<cm:content>contentUrl=classpath:alfresco/module/bootstrap-content-repo/bootstrap/someacmedoc.txt|mimetype=text/plain|size=30|encoding=UTF-8|locale=en_GB_</cm:content>
		<acme:documentId>DOC001</acme:documentId>
		<cm:title>
			<view:mlvalue view:locale="en">SomeTitle</view:mlvalue>
		</cm:title>
		<cm:modified>2015-09-10T16:11:07.875+01:00</cm:modified>
		<sys:node-uuid>34e4a654-b45e-4be1-80db-25da1e4c82a7</sys:node-uuid>
		<app:editInline>true</app:editInline>
		<cm:created>2015-09-10T16:10:49.142+01:00</cm:created>
		<sys:store-protocol>workspace</sys:store-protocol>
		<cm:creator>admin</cm:creator>
		<cm:description>
			<view:mlvalue view:locale="en">SomeDesc</view:mlvalue>
		</cm:description>
		<cm:modifier>admin</cm:modifier>
	</view:properties>
</acme:document>
</view:view>

Besides using patches to bootstrap content there is also the ImporterModuleComponent that can be used to bootstrap/import content into the Repository, for more information about this see Module Components.

More info on bootstrapping folders and files

It is possible to bootstrap files and spaces (i.e. folders) by using XML files.

An alternative to the ACP import is to explicitly reference files through XML.

<bean id="customSpacesBootstrap" parent="spacesStoreImporter" singleton="true" >
  <property name="useExistingStore">
    <value>${yourmodule.bootstrap.data}</value>
  </property>
  <property name="bootstrapViews">
    <list>
      <props>
        <prop key="path">/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.templates.email.childname}</prop>
        <prop key="location">alfresco/module/yourmodule/bootstrap/config_email_templates.xml</prop>
      </props>
    </list>
  </property>
</bean>

In the code sample, config_email_templates.xml contains the actual file references, as well as all file and folder properties. All predetermined files and folders will be placed in the Company Home/Data Dictionary/Email Templates space.

Property values

useExistingStore If false the content will not be imported if the store exists
bootstrapViews What you want to import and where it comes from

It is convenient to use a global property value for the property useExistingStore in order to control bootstrapping on Content Services startup. If the store does not yet exist (the very first time a new Content Services installation starts up), the data will aways be bootstrapped, no matter the value, but from that moment on the store exists, and setting this to false means the next time Content Services reboots these files will not be overridden with those on the classpath. Set it to true again and on the next reboot the classpath files are loaded.

XML imports can only replace/update/delete files that have their UUID set.

Examples of how to bootstrap data to other stores or to see all the available options, can be found in the file import-export-context.xml.

Another example is shown here:

<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
  xmlns:cm="http://www.alfresco.org/model/content/1.0" xmlns:app="http://www.alfresco.org/model/application/1.0"
  xmlns:emailserver="http://www.alfresco.org/model/emailserver/1.0">
  
  <cm:folder view:childName="cm:My First Folder">
    <app:uifacets />
    <cm:name>My First Folder</cm:name>
    <app:icon>space-icon-default</app:icon>
    <cm:title>My First Folder</cm:title>
    <cm:description></cm:description>
    <cm:contains>
      <cm:content view:childName="cm:custom_email_template.ftl">
        <view:aspects>
          <cm:titled />
          <cm:author />
          <app:inlineeditable />
        </view:aspects>
        <view:properties>
          <app:editInline>true</app:editInline>
          <cm:description>This is a custom email template.</cm:description>
          <cm:content>contentUrl=classpath:alfresco/module/yourmodule/bootstrap/custom_email_template.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=en_US_</cm:content>
          <cm:title>My first email template</cm:title>
          <cm:author>Me</cm:author>
          <cm:name>custom_email_template.ftl</cm:name>
        </view:properties>
        <view:associations></view:associations>
      </cm:content>
    </cm:contains>
  </cm:folder>
</view:view>

In the code sample, you see a folder is being added, containing a single FreeMarker template file. You can add multiple files and folders on the top level, or in sub-folders this way. Aspects can also be set on the new folder. Another example can be found in the file config/alfresco/bootstrap/spaces.xml. The bootstrap directory also contains many other examples.

Bootstrapping categories

Categories can be bootstrapped by using an XML file.

Your categories bootstrap XML file must contain only cm:generalclassifiable categories. An example of the XML file is provided as follows:

<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
  xmlns:sys="http://www.alfresco.org/model/system/1.0"
  xmlns:cm="http://www.alfresco.org/model/content/1.0">
  
  <cm:category>
    <cm:name>Your Root Category</cm:name>
    <cm:subcategories>
      <cm:category>
        <cm:name>Your Parent Category</cm:name>
        <cm:subcategories>
          <cm:category>
            <cm:name>Your Child Category</cm:name>
          </cm:category>
        </cm:subcategories>
      </cm:category>
    </cm:subcategories>
  </cm:category>
</view:view>

Bootstrap/Import Module Data

As part of your content model and module, you can import some data that the module uses. These can be, for example, Categories, FTL scripts in the data dictionary, project template hierarchies, ACP files.

For many content models, it is useful to have some data populated when the model is loaded. This is done by bootstrapping some data. One good example is in the Records Management module.

You can import the data by using an XML file or an ACP file as part of your module’s initialization.

First place your ACP or XML file somewhere in your module’s classpath. Often this will be within the aio/aio-platform-jar/src/main/resources/alfresco/module/aio-platform-jar/bootstrap folder structure. Next add the following configuration to your aio/aio-platform-jar/src/main/resources/alfresco/module/aio-platform-jar/context/bootstrap-context.xml file, specifying either the XML or ACP file by its location on the classpath.

<bean id="myModule.bootstrap" 
  class="org.alfresco.repo.module.ImporterModuleComponent" 
  parent="module.baseComponent">
  
  <!-- Module Details -->
  <property name="moduleId" value="myModule" />
  <property name="name" value="myModuleBootstrap" />
  <property name="description" value="My Modules initial data requirements" />
  <property name="sinceVersion" value="1.0" />
  <property name="appliesFromVersion" value="1.0" />
  
  <!-- Data properties -->
  <property name="importer" ref="spacesBootstrap"/>
  <property name="bootstrapViews">
    <list>
      <props>
        <prop key="path">/${spaces.company_home.childname}</prop>
        <prop key="location">alfresco/module/myModule-123/myACP.acp</prop>
      </props>
    </list>
  </property>
  
</bean>

Key property values are shown in the following table:

Property Name Description
moduleId The ID of the module that this import component relates to.
name The name of the import component.
description A description of the import component.
sinceVersion The version of the module this import component was introduced.
appliesFromVersion The version of the module from which this import component applies from.
importer The importer to use when importing the data
bootstrapViews A list of the ACP or XML files to be imported and the location in the destination repository where the data should be imported.

Import strategy

There are several import strategies that can be used to import module data.

If you know the UUID(s) of the spaces/files you are importing, you can choose from a number of import strategies.

If you are using XML, you will have to manually add a sys:node-uuid tag to that node. (Generated ACP files automatically contain the UUIDs.)

Example:

    <view:properties>
        <sys:node-uuid>b7c6b88a-e5fd-4ccf-b134-69a2460c3b89</sys:node-uuid>
        ...
    </view:properties>
</cm:content>
</cm:contains>
</cm:folder>
</view:view>

You can add the following: CREATE_NEW, CREATE_NEW_WITH_UUID, REMOVE_EXISTING, REPLACE_EXISTING, UPDATE_EXISTING, THROW_ON_COLLISION (org.alfresco.service.cmr.view.ImporterBinding.UUID_BINDING). This can be added globally for entire bean, or per bootstrap view.

Global for the entire bean:

<bean id="myModule.bootstrap" 
  class="org.alfresco.repo.module.ImporterModuleComponent" 
  parent="module.baseComponent">
  <property name="uuidBinding">
    <value>REPLACE_EXISTING</value>
  </property>
  ...

Per BootstrapView:

  <property name="bootstrapViews">
    <list>
      <props>
        <prop key="uuidBinding">UPDATE_EXISTING</prop>
        <prop key="path">/${spaces.company_home.childname}/${spaces.dictionary.childname}</prop>
        <prop key="location">alfresco/module/yourmodule/bootstrap/myimport.acp</prop>
      </props>
      ...
    </list>
  </property>
</bean>

Space Names Reference

The following are the substitution tokens that can be used for bootstrapping purposes. These tokens can be redefined in the configuration files if needed.

spaces.store workspace://SpacesStore
spaces.company_home.childname Company Home
spaces.guest_home.childname Guest Home
spaces.dictionary.childname Data Dictionary
spaces.templates.childname Space Templates
spaces.templates.content.childname Content Templates
spaces.templates.email.childname Email Templates
spaces.templates.rss.childname RSS Templates
spaces.savedsearches.childname Saved Searches
spaces.scripts.childname Scripts
spaces.wcm.childname WCM
spaces.wcm_content_forms.childname Web Forms
spaces.content_forms.childname Web Forms
spaces.user_homes.childname User Homes

Deployment - App Server

  • XML, ACP, and content files: tomcat/shared/classes/alfresco/extension/... (File name can be anything you like as long as you refer to it in the Spring context file)
  • Spring Beans: tomcat/shared/classes/alfresco/extension/my-content-model-context.xml (File name has to end in -context.xml to be picked up as Spring Bean context file)

These file locations are untouched by re-deployments and upgrades.

Deployment All-in-One SDK project

  • XML, ACP, and content files: aio/platform-jar/src/main/resources/alfresco/module/platform-jar/bootstrap
  • Spring Beans: aio/platform-jar/src/main/resources/alfresco/module/platform-jar/context/bootstrap-context.xml

More Information

Sample Code

Edit this page

Suggest an edit on GitHub
This website uses cookies in order to offer you the most relevant information. Please accept cookies for optimal performance. This documentation is subject to the Documentation Notice.