JBoss Portal packages a Web Content Management System capable of serving and allowing administration of web content. This chapter describes the CMS Portlet which is responsible for serving resources requested, the following chapter describes the CMSAdmin Portlet and all administration functionality.
The CMS Portlet displays content from the file store inside a portlet window, or, in the case of binary content, outside of the portlet window altogether.
The CMSPortlet handles all requests for all content types.
The methodology of serving content within the CMSPortlet, allows for some beneficial features, like:
Since 2.6 displaying CMS content in the portal is done using the new content integration feature. Each window of the portal can be configured to display CMS content directly instead of having to configure the CMS portlet as it used to be.
Showing CMS content in a portal window can be done in the deployment descriptor quite easily
<window> <window-name>MyCMSWindow</window-name> <content> <content-type>cms</content-type> <content-uri>/default/index.html</content-uri> </content> <region>center</region> <height>1</height> </window>
At the first display of the window, the content is initialized with the content uri value. When the user clicks on a link that navigates to another CMS file, the CMS file will be shown in the same window.
Since 2.6 displaying CMS content in the portal is done using the new content integration feature. The portal is also able to map urls content to the CMS through a specific window. The CMS portlet default page is defined as a preference and can be overriden like any other preference up to the user's preference level. The default CMS portlet displayed when you install JBoss Portal for the first time is describe in the following file: jboss-portal.sar/portal-core.war/WEB-INF/portlet.xml .
<portlet-preferences> <preference> <name>indexpage</name> <value>/default/index.html</value> </preference> </portlet-preferences>
The preference key is "indexpage". To change the default page, just make sure to create an html document using the CMS Admin portlet then change the value of "indexpage" to the corresponding path.
JBoss Portal uses Apache Jackrabbit as its Java Content Repository implementation. Configuration of the service descriptor, allows for changing many of the variables associated with the service.
Here is the default configuration for the CMS repository found under portal-cms.sar/META-INF-INF/jboss-service.xml
... <attribute name="DoChecking">true</attribute> <attribute name="DefaultContentLocation">portal/cms/conf/default-content/default/</attribute> <attribute name="DefaultLocale">en</attribute> <attribute name="RepositoryName">PortalRepository</attribute> <attribute name="HomeDir">${jboss.server.data.dir}${/}portal${/}cms${/}conf</attribute> ...
Below is a list of items found in the service descriptor and their definitions. Only items commonly changed are covered here and it is recommended you do not change any others unless you are very brave.
By default, the content will be accessible to a url like this: http://www.example.com/content/[...], if you need or prefer to change "content" to something else you will need to edit the following file: portal-cms.sar/META-INF-INF/jboss-service.xml and change the value of Prefix to something else. Please note that you cannot change it to "nothing", you need to provide a value.
... <mbean code="org.jboss.portal.core.cms.CMSObjectCommandFactory" name="portal:commandFactory=CMSObject" xmbean-dd="" xmbean-code="org.jboss.portal.common.system.JBossServiceModelMBean"> <xmbean/> <attribute name="Prefix">content</attribute> <attribute name="TargetWindowRef">default.default.CMSPortletWindow</attribute> <depends optional-attribute-name="Factory" proxy-type="attribute"> portal:commandFactory=Delegating </depends> <depends optional-attribute-name="CMSService" proxy-type="attribute"> portal:service=CMS </depends> </mbean> ...
By default, the JBoss Portal CMS stores all node properties, references, and binary content in the database, using the portal datasource. The location of some of these items is configurable, and there are 3 options:
To enable 100% Filesystem storage, you must edit the file: jboss-portal.sar/portal-cms.sar/META-INF/jboss-service.xml . You will note that the file is set to use the HibernateStore and HibernatePersistenceManager classes, by default. To have the CMS use 100% file system storage, simply comment these blocks. Then, you should uncomment to use the LocalFileSystem and XMLPersistenceManager classes. Follow these steps to activate 100% FS storage:
Comment out the following blocks (there are 3 in total):
<!-- HibernateStore: uses RDBMS + Hibernate for storage --> <FileSystem class="org.jboss.portal.cms.hibernate.HibernateStore"> ... </FileSystem>
And uncomment the blocks under them (there are 3 in total):
<!-- LocalFileSystem: uses FileSystem for storage. --> <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem"> ... </FileSystem>
Now comment out the following blocks (there are 2 in total):
<!-- HibernatePersistentManager: uses RDBMS + Hibernate for storage --> <PersistenceManager class="org.jboss.portal.cms.hibernate.state.HibernatePersistenceManager"> ... </PersistenceManager>
And uncomment the blocks under them (there are 2 in total):
<!-- XMLPersistenceManager: uses FileSystem for storage --> <PersistenceManager class="org.apache.jackrabbit.core.state.xml.XMLPersistenceManager"/>
This is the default configuration for the CMS store. Please view the original jboss-portal.sar/portal-cms.sar/META-INF/jboss-service.xml , for guidance on how to reset it.
Mixed storage consists of meta-data being stored in the DB and blobs being stored on the Filesystem. This is the recommended setting for those of you that serve large files or stream media content.
Setting the repository this way is simple. Change every instance in the file jboss-portal.sar/portal-cms.sar/META-INF/jboss-service.xml , from:
<param name="externalBLOBs" value="false"/>
to:
<param name="externalBLOBs" value="true"/>
The CMS Portlet now serves content based on the user's locale setting. For example: if a user's locale is set to Spanish in his browser, and he requests URL: default/index.html , the CMSPortlet will first try and retrieve the Spanish version of that file. If a Spanish version is not found, it will then try and retrieve the default language version set for the CMSPortlet.
The CMS portlet calls a CMS service that can be reused in your own portlets.
Since JBoss Portal 2.4 you can add your own interceptor stack to the CMS service. The interceptors are called around each command (Get a file, write a file, create a folder...), this is a very easy way to customize some actions based on your needs.
To create your own interceptor you just need to extend the org.jboss.portal.cms.CMSInterceptor class and provide the content of the invoke(JCRCommand) method. Do not forget to make a call to JCRCommand.invokeNext() or the command will never be executed.
JBoss Portal relies on the interceptor mechanism to integrate its Fine Grained Security Service and the Publish/Approve Workflow Service
To add or remove an interceptor, you just need to edit the following file: portal-cms-sar/META-INF/jboss-service.xml. It works the same way as the server interceptor, for each interceptor you need to define an mbean then add it to the cms interceptor stack. For example, if you have the 2 default interceptors, you should have the following lines in the jboss-service.xml file:
<!-- ACL Security Interceptor --> <mbean code="org.jboss.portal.cms.impl.interceptors.ACLInterceptor" name="portal:service=Interceptor,type=Cms,name=ACL" xmbean-dd="" xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean"> <xmbean /> <attribute name="JNDIName"> java:/portal/cms/ACLInterceptor </attribute> <attribute name="CmsSessionFactory"> java:/portal/cms/CMSSessionFactory </attribute> <attribute name="IdentitySessionFactory"> java:/portal/IdentitySessionFactory </attribute> <attribute name="DefaultPolicy"> <policy> <!-- permissions on the root cms node --> <criteria name="path" value="/"> <permission name="cms" action="read"> <role name="Anonymous" /> </permission> <permission name="cms" action="write"> <role name="User" /> </permission> <permission name="cms" action="manage"> <role name="Admin" /> </permission> </criteria> <!-- permissions on the default cms node --> <criteria name="path" value="/default"> <permission name="cms" action="read"> <role name="Anonymous" /> </permission> <permission name="cms" action="write"> <role name="User" /> </permission> <permission name="cms" action="manage"> <role name="Admin" /> </permission> </criteria> <!-- permissions on the private/protected node --> <criteria name="path" value="/default/private"> <permission name="cms" action="manage"> <role name="Admin" /> </permission> </criteria> </policy> </attribute> <depends optional-attribute-name="AuthorizationManager" proxy-type="attribute"> portal:service=AuthorizationManager,type=cms </depends> <depends>portal:service=Hibernate,type=CMS</depends> <depends> portal:service=Module,type=IdentityServiceController </depends> </mbean> <!-- Approval Workflow Interceptor --> <mbean code="org.jboss.portal.cms.impl.interceptors.ApprovalWorkflowInterceptor" name="portal:service=Interceptor,type=Cms,name=ApprovalWorkflow" xmbean-dd="" xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean"> <xmbean /> <attribute name="JNDIName"> java:/portal/cms/ApprovalWorkflowInterceptor </attribute> <depends>portal:service=Hibernate,type=CMS</depends> </mbean> <!-- CMS Interceptor Registration --> <mbean code="org.jboss.portal.server.impl.invocation.JBossInterceptorStackFactory" name="portal:service=InterceptorStackFactory,type=Cms" xmbean-dd="" xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean"> <xmbean /> <depends-list optional-attribute-name="InterceptorNames"> <depends-list-element> portal:service=Interceptor,type=Cms,name=ACL </depends-list-element> <depends-list-element> portal:service=Interceptor,type=Cms,name=ApprovalWorkflow </depends-list-element> </depends-list> </mbean>
The first two mbeans define the interceptors and the third mbean, define which interceptors to add to the CMS service.
If you create your own interceptor org.example.myCMSInterceptor, the service descriptor file will look like:
<mbean code="org.example.myCMSInterceptor" name="portal:service=Interceptor,type=Cms,name=MyName" xmbean-dd="" xmbean-code="org.jboss.portal.common.system.JBossServiceModelMBean"> <xmbean /> </mbean> <!-- ACL Security Interceptor --> <mbean code="org.jboss.portal.cms.impl.interceptors.ACLInterceptor" name="portal:service=Interceptor,type=Cms,name=ACL" xmbean-dd="" xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean"> <xmbean /> <attribute name="JNDIName"> java:/portal/cms/ACLInterceptor </attribute> <attribute name="CmsSessionFactory"> java:/portal/cms/CMSSessionFactory </attribute> <attribute name="IdentitySessionFactory"> java:/portal/IdentitySessionFactory </attribute> <attribute name="DefaultPolicy"> <policy> <!-- permissions on the root cms node --> <criteria name="path" value="/"> <permission name="cms" action="read"> <role name="Anonymous" /> </permission> <permission name="cms" action="write"> <role name="User" /> </permission> <permission name="cms" action="manage"> <role name="Admin" /> </permission> </criteria> <!-- permissions on the default cms node --> <criteria name="path" value="/default"> <permission name="cms" action="read"> <role name="Anonymous" /> </permission> <permission name="cms" action="write"> <role name="User" /> </permission> <permission name="cms" action="manage"> <role name="Admin" /> </permission> </criteria> <!-- permissions on the private/protected node --> <criteria name="path" value="/default/private"> <permission name="cms" action="manage"> <role name="Admin" /> </permission> </criteria> </policy> </attribute> <depends optional-attribute-name="AuthorizationManager" proxy-type="attribute"> portal:service=AuthorizationManager,type=cms </depends> <depends>portal:service=Hibernate,type=CMS</depends> <depends> portal:service=Module,type=IdentityServiceController </depends> </mbean> <!-- Approval Workflow Interceptor --> <mbean code="org.jboss.portal.cms.impl.interceptors.ApprovalWorkflowInterceptor" name="portal:service=Interceptor,type=Cms,name=ApprovalWorkflow" xmbean-dd="" xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean"> <xmbean /> <attribute name="JNDIName"> java:/portal/cms/ApprovalWorkflowInterceptor </attribute> <depends>portal:service=Hibernate,type=CMS</depends> </mbean> <mbean code="org.jboss.portal.server.impl.invocation.JBossInterceptorStackFactory" name="portal:service=InterceptorStackFactory,type=Cms" xmbean-dd="" xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean"> <xmbean /> <depends-list optional-attribute-name="InterceptorNames"> <depends-list-element> portal:service=Interceptor,type=Cms,name=ACL </depends-list-element> <depends-list-element> portal:service=Interceptor,type=Cms,name=ApprovalWorkflow </depends-list-element> </depends-list> </mbean> <!-- CMS Interceptor Registration --> <mbean code="org.jboss.portal.server.impl.invocation.JBossInterceptorStack" name="portal:service=InterceptorStack,type=Cms" xmbean-dd="" xmbean-code="org.jboss.portal.common.system.JBossServiceModelMBean"> <xmbean /> <depends-list optional-attribute-name="InterceptorNames"> <depends-list-element> portal:service=Interceptor,type=Cms,name=ACL </depends-list-element> <depends-list-element> portal:service=Interceptor,type=Cms,name=ApprovalWorkflow </depends-list-element> <depends-list-element> portal:service=Interceptor,type=Cms,name=MyName </depends-list-element> </depends-list> </mbean>
The interceptor order is important !
To check that the interceptors have been correctly added, you can check the JMX console, by going to: http://localhost.localdomain:8080/jmx-console/HtmlAdaptor?action=inspectMBean&name=portal%3Aservice%3DInterceptorStack%2Ctype%3DCms You should notice all the interceptors in the attribute "interceptors".