Статьи

Создание индивидуального решения с порталом JBoss

Изначально проект JBoss Portal предоставляет простой портал, обычно пользователи полностью его урезают и начинают заново или строят поверх него. В этой статье мы увидим, как постепенно преобразовать готовый портал в индивидуальное решение.

 

От:

Для того, чтобы:

Смена темы

Первое, что мы сделаем, это изменим визуальный аспект портала. Портал JBoss разделяет макет (как формируется страница) и его художественный аспект (обычно файл CSS). В этом примере мы создадим как новый макет, так и новую тему (или скин). Для этой статьи мы нашли существующую тему, разработанную для блога под лицензией общественного достояния, которую можно найти здесь: http://www.opendesigns.org/design/?template=1090

Загруженный файл был составлен из статического HTML страницу, файл CSS и несколько изображений, а затем их было легко адаптировать, нам просто нужно было удалить статические части, чтобы добавить динамические. HTML-страница стала нашим макетом, а CSS-файл — нашим скином. Также, так как мы хотели иметь три разных макета в конце, мы разделили документы на части верхнего и нижнего колонтитула.

Вот здесь графическое описание разделения, обведенное красным, мы видим заголовок (нижний колонтитул не помещается на странице), вверху в зеленом прямоугольнике мы видим позицию, куда мы хотим включить ссылки, слева две области столбца, где мы хотим поместить окна и справа другой регион для других окон. Вверху правого региона мы добавили место для ссылок входа / выхода.

Наш макет из трех колонок теперь выглядит так:

<%@ taglib uri="/WEB-INF/theme/portal-layout.tld" prefix="p" %>
<%@include file="/layouts/common/header.jsp"%>

<p:region regionName='FirstColumn' regionID='linkbar'/>
<p:region regionName='SecondColumn' regionID='left'/>

<div id="right">

<div class="content">

<!-- Utility controls -->
<p:region regionName='dashboardnav' regionID='dashboardnav'/>

<p:region regionName='MainColumn'/>
</div>
</div>
<%@include file="/layouts/common/footer.jsp"%>

Как мы видим, мы использовали специальную библиотеку тегов JBoss Portal для определения мест, где структура портала должна включать регион, который мы называем FirstColumn, регион с именем dashboardnav (который будет включать ссылки на вход / выход из системы) и регион с именем SecondColumn. Связанный CSS (который является стандартным CSS) будет отображать вещи так, как мы хотим. Этот макет не определяет, как мы хотим, чтобы окна отображались.
На следующем изображении мы видим, как разлагается страница, мы видели, как объявить, где в разметке мы хотим включить регионы. Нам все еще нужно определить, какую разметку мы хотим определить для области, разметки для каждого окна, разметки для оформления окна, которая обычно состоит из заголовка окна и ссылок для режимов портлета и для разметки вокруг содержимого, заданного самим портлетом.

В нашем случае мы не хотим никакого оформления окна, кроме заголовка окна. У нас могут быть различные виды декораций окон, но для нас важно иметь возможность повторно использовать их на портале.
Мы определим класс для всех четырех элементов: области, окна, декорации и портлета, реализующих интерфейсы Java org.jboss. .portal.theme.render.renderer.RegionRenderer, WindowRenderer, DecorationRenderer и PortletRenderer. В нашем примере мы можем найти классы в org.jboss.portal.myportal.theme. *
Давайте просто посмотрим на наш WindowRenderer, который просто добавляет тег «div» вокруг окна, а затем делегирует рендеринг оформления и рендлет портлета.

package org.jboss.portal.myPortal.theme;

import [...]
import org.jboss.portal.theme.render.AbstractObjectRenderer;
import org.jboss.portal.theme.render.renderer.WindowRenderer;
import org.jboss.portal.theme.render.renderer.WindowRendererContext;

public class DivWindowRenderer extends AbstractObjectRenderer
implements WindowRenderer
{
public void render(RendererContext rendererContext, WindowRendererContext wrc) throws RenderException
{
Writer writer = rendererContext.getWriter();
try {
writer.write("<div>");
rendererContext.render(wrc.getDecoration());
rendererContext.render(wrc.getPortlet());
writer.write("</div>");
} catch (IOException e) {
e.printStackTrace();
}
}
}

Средство визуализации декораций просто отображает заголовок окна:

package org.jboss.portal.myPortal.theme;

import [...]
import org.jboss.portal.theme.render.AbstractObjectRenderer;
import org.jboss.portal.theme.render.RenderException;
import org.jboss.portal.theme.render.RendererContext;
import org.jboss.portal.theme.render.renderer.DecorationRenderer;
import org.jboss.portal.theme.render.renderer.DecorationRendererContext;

public class DivDecorationRenderer extends AbstractObjectRenderer
implements DecorationRenderer
{

public void render(RendererContext rendererContext, DecorationRendererContext drc) throws RenderException
{
PrintWriter out = rendererContext.getWriter();

out.println("<span class=\"headline_three\">" + drc.getTitle() + "</span><br />");
}

}

Теперь мы определили всю разметку и CSS, необходимые для отображения содержимого. Мы объединили эти классы в JAR и добавили статические ресурсы в WAR. Единственное, что осталось для тематической части, это объявить наш новый макет и скин. Для этого нам нужно добавить несколько дескрипторов. Сначала нам нужно объявить набор визуализации, который представляет собой набор средств визуализации. С помощью этих наборов рендеринга мы можем комбинировать несколько существующих рендеров для выбора, так как мы будем строить портал.
В нашем myPortal.war / WEB-INF / layout / portal-renderSet.xml мы дадим имя нашему новому набору визуализации и определим все используемые средства визуализации:

<portal-renderSet>
<renderSet name="myPortalRenderer">
<set content-type="text/html">
<ajax-enabled>false</ajax-enabled>
<region-renderer>org.jboss.portal.myPortal.theme.DivRegionRenderer</region-renderer>
<window-renderer>org.jboss.portal.myPortal.theme.DivWindowRenderer</window-renderer>
<portlet-renderer>org.jboss.portal.myPortal.theme.DivPortletRenderer</portlet-renderer>
<decoration-renderer>org.jboss.portal.myPortal.theme.DivDecorationRenderer</decoration-renderer>
</set>
</renderSet>
</portal-renderSet>
Now we need to define our layouts in myPortal.war/WEB-INF/portal-layouts.xml:
<layouts>
<layout>
<name>MyLayout</name>
<uri>/layouts/myLayout.jsp</uri>
<uri state="maximized">/layouts/myMaximizedLayout.jsp</uri>
<regions>
<region name="FirstColumn"/>
<region name="SecondColumn"/>
<region name="MainColumn"/>
</regions>
</layout>
<layout>
<name>TwoColumnsLayout</name>
<uri>/layouts/twoColumnsLayout.jsp</uri>
<uri state="maximized">/layouts/myMaximizedLayout.jsp</uri>
<regions>
<region name="FirstColumn"/>
<region name="SecondColumn"/>
</regions>
</layout>
</layouts>

И последнее, но не менее важное: давайте определим наш скин в myPortal.war / WEB-INF / portal-themes.xml и дадим ему имя.

<themes>
<theme>
<name>mySkin</name>
<link href="/skins/mySkin.css" title="" rel="stylesheet" type="text/css" media="screen" />
</theme>
</themes>

Развернув эту войну на готовом портале, мы уже сможем изменить тему по умолчанию, используя, например, портлет администратора.

Применительно к первой странице это будет выглядеть как следующий скриншот. Поскольку названия регионов изменились с исходной страницы, существующие окна не отображаются, но ссылки на другие страницы находятся здесь со ссылками на вход / выход из системы.
Та же страница, после добавления некоторых портлетов / контента CMS, который хорошо вписывается в тему.

Но мы еще не совсем там, локализация не была обработана, ни как добавить контент, получить надлежащую декларативную безопасность и кэширование.

Добавление контента

Для этой статьи мы создали простой RSS-портлет, который может отображать список из последних n записей в блоге или полный контент статьи (если он указан в ленте). Это можно найти в проекте rssPortlet. Мы не будем вдаваться в подробности самого портлета, это стандартный портлет JSR-286, который поддерживает два параметра: «rssFeed», который содержит URL-адрес RSS-канала, и «limit», который является максимальным количеством отображаемых записей. ,
Здесь важно то, как мы можем добавить окна, используя этот портлет, и для этой статьи мы не хотим использовать портлет администратора, но мы хотим иметь возможность доставить портал кому-то, чтобы при первом запуске он заполнил свою базу данных. с правильными значениями. Затем мы будем использовать XML для определения нашего портала. В нашем веб-архиве портлетов мы включаем файл с именем WEB-INF / portlet-instances.xml, который будет использоваться для создания настраиваемых экземпляров портлета.
Файл довольно понятен, мы создаем три экземпляра для разных каналов с разными значениями для отображения RSS. Обратите внимание, что последний экземпляр имеет ограничение безопасности, это декларативный способ показать этот экземпляр только пользователям с ролью администратора.

<!DOCTYPE deployments PUBLIC
"-//JBoss Portal//DTD Portlet Instances 2.6//EN"
"http://www.jboss.org/portal/dtd/portlet-instances_2_6.dtd">

<deployments>
<deployment>
<instance>
<instance-id>JBossPortalRSSInstance</instance-id>
<portlet-ref>MyRSSPortlet</portlet-ref>
<preferences>
<preference>
<name>rssFeed</name>
<value>
http://feeds.feedburner.com/jbossportal
</value>
</preference>
<preference>
<name>limit</name>
<value>10</value>
</preference>
</preferences>
</instance>
</deployment>
<deployment>
<instance>
<instance-id>JBossRSSInstance</instance-id>
<portlet-ref>MyRSSPortlet</portlet-ref>
<preferences>
<preference>
<name>rssFeed</name>
<value>http://labs.jboss.org/feeds/all/atom</value>
</preference>
<preference>
<name>limit</name>
<value>10</value>
</preference>
</preferences>
</instance>
</deployment>
<deployment>
<instance>
<instance-id>AdminOnlyRSSInstance</instance-id>
<portlet-ref>MyRSSPortlet</portlet-ref>
<security-constraint>
<policy-permission>
<action-name>view</action-name>
<role-name>Admin</role-name>
</policy-permission>
</security-constraint>
<preferences>
<preference>
<name>rssFeed</name>
<value><![CDATA[http://pipes.yahoo.com/pipes/pipe.run?_id=fb3504450e04190b33a8ef9628599c76&_render=rss&forumurl=215]]></value>
</preference>
<preference>
<name>limit</name>
<value>10</value>
</preference>
</preferences>
</instance>
</deployment>
</deployments>

С этими экземплярами портлета мы сможем добавить их в окна, которые будут составлять наши страницы. Мы решили сохранить композицию нашего портала вместе с новой темой в myPortal.war. Интересующий нас файл находится по адресу myPortal.war / WEB-INF / default-object.xml. Поскольку слишком долго полностью посвящать эту статью, мы рассмотрим некоторые ее части.
Первое развертывание — это сам контекст, корень всех порталов, где все значения по умолчанию могут быть определены, поскольку любой дочерний объект будет наследоваться от контекста. Здесь мы определяем, что мы хотим использовать наш новый макет, наш новый скин, наш набор визуализации и определите имя портала, который будет использоваться по умолчанию (здесь мы назовем его «default»).

<deployments>
<deployment>
<context>
<context-name />
<properties>
<!--
| Set the layout for the default portal, see also portal-layouts.xml.
-->
<property>
<name>layout.id</name>
<value>MyLayout</value>
</property>
<!--
| Set the theme for the default portal, see also portal-themes.xml.
-->
<property>
<name>theme.id</name>
<value>mySkin</value>
</property>
<!--
| Set the default render set name (used by the render tag in layouts), see also portal-renderSet.xml
-->
<property>
<name>theme.renderSetId</name>
<value>myPortalRenderer</value>
</property>
<!--
| The default portal name, if the property is not explicited then the default portal name is "default"
-->
<property>
<name>portal.defaultObjectName</name>
<value>default</value>
</property>
[...]
</context>
</deployment>

Следующее развертывание — наш портал по умолчанию, мы определяем наши страницы и окна. Посмотрите, как мы определяем окно со ссылкой на идентификатор портлета (или ссылку на CMS, ссылку на гаджет …)., Имя региона, в котором нужно разместить окно, и номер для определения порядка внутри региона.
Мы также можем заметить, что вторая страница переопределяет значение для макета, чтобы использовать макет из двух столбцов, который мы определили, вместо макета из трех столбцов по умолчанию, который мы видели ранее.
Все страницы этого фрагмента имеют право на просмотр кем-либо.

    <deployment>
<parent-ref />
<if-exists>overwrite</if-exists>
<portal>
<portal-name>default</portal-name>
<supported-modes>
<mode>view</mode>
<mode>edit</mode>
<mode>help</mode>
</supported-modes>
<supported-window-states>
<window-state>normal</window-state>
<window-state>minimized</window-state>
<window-state>maximized</window-state>
</supported-window-states>
<security-constraint>
<policy-permission>
<action-name>view</action-name>
<unchecked />
</policy-permission>
</security-constraint>
[...]
<page>
<page-name>default</page-name>
<display-name xml:lang="en">Home</display-name>
<display-name xml:lang="fr">Page de Garde</display-name>
<security-constraint>
<policy-permission>
<action-name>view</action-name>
<unchecked />
</policy-permission>
</security-constraint>

<properties>
<property>
<name>order</name>
<value>0</value>
</property>
</properties>
<window>
<window-name>JBossPortalRSSWindow</window-name>
<instance-ref>JBossPortalRSSInstance</instance-ref>
<region>FirstColumn</region>
<height>0</height>
</window>
<window>
<window-name>JBossRSSWindow</window-name>
<instance-ref>JBossRSSInstance</instance-ref>
<region>SecondColumn</region>
<height>0</height>
</window>
<window>
<window-name>CMSWindow</window-name>
<content>
<content-type>cms</content-type>
<content-uri>/default/index.html</content-uri>
</content>
<region>MainColumn</region>
<height>1</height>
</window>
</page>
<page>
<page-name>otherpage</page-name>
<display-name xml:lang="en">Other Page</display-name>
<display-name xml:lang="fr">Autre Page</display-name>
<security-constraint>
<policy-permission>
<action-name>view</action-name>
<unchecked />
</policy-permission>
</security-constraint>
<properties>
<property>
<name>order</name>
<value>1</value>
</property>
<property>
<name>layout.id</name>
<value>TwoColumnsLayout</value>
</property>
<property>
<name>theme.id</name>
<value>mySkin</value>
</property>
</properties>
<window>
<window-name>SudokuWindow</window-name>
<content>
<content-type>widget/netvibes</content-type>
<content-uri>
http://sudokushark.com/netvibes_uwa.php
</content-uri>
</content>
<region>FirstColumn</region>
<height>0</height>
</window>
<window>
<window-name>JBossForumRSSWindow</window-name>
<instance-ref>AdminOnlyRSSInstance</instance-ref>
<region>SecondColumn</region>
<height>0</height>
</window>
</page>
[...]
</portal>
</deployment>

Прежде чем мы развернем это в JBoss Portal, мы должны удалить стандартную конфигурацию по умолчанию, это можно сделать, удалив jboss-portal.sar / conf / data / default-object.xml. Также мы должны очистить нашу базу данных, удалив jboss-4.2.3 / server / default / data, чтобы убедиться, что наш контент будет синхронизирован с тем, что мы здесь описали.
Также мы хотим настроить некоторый контент CMS, опять же, мы могли бы создать контент через портлет CMS Admin, но здесь мы просто хотим добавить контент при запуске.
Декларативная безопасность и кэширование
Мы уже видели, как мы можем ограничить экземпляр портлета для конкретной роли, ниже приведено частичное определение страницы, которая ограничена ролью «admin». Любой зарегистрированный обычный пользователь не сможет получить доступ к странице.

            <page>
<page-name>admin</page-name>
<display-name xml:lang="en">Admin Only</display-name>
<display-name xml:lang="fr">Pour Admins</display-name>
<security-constraint>
<policy-permission>
<action-name>view</action-name>
<role-name>Admin</role-name>
</policy-permission>
</security-constraint>
[...]
</page>

Еще одна особенность — возможность определения кэширования фрагментов страницы. Есть случаи, когда вызывать фазу рендеринга портлета не имеет смысла, так как содержимое не будет меняться со временем или не часто. Наш RSS-портлет является типичным примером, и здесь мы хотим кэшировать содержимое портлета в течение 10 минут, чтобы избежать ненужных дорогостоящих вызовов к каналу.
Используя стандартный дескриптор portlet.xml, мы добавляем кэш истечения в секундах:
   

   <portlet>
<description>My RSS Portlet</description>
<portlet-name>MyRSSPortlet</portlet-name>
<display-name>My RSS Portlet</display-name>
<portlet-class>org.jboss.portal.rssPortlet.RSSPortlet</portlet-class>
<expiration-cache>600</expiration-cache>
[...]

На этом этапе мы создали портал с организованным контентом, безопасностью и кэшированием.

Изменение внутренних органов

Портал «из коробки» определяет языковой стандарт пользователя из профиля пользователя. Если в пользовательском профиле не установлен предпочтительный язык, используется язык, установленный его веб-браузером.
На нашем демонстрационном портале мы хотим, чтобы пользователь нажимал на флажки. Это наше требование.
Чтобы реализовать это требование, мы решили сохранить выбранную локаль в сеансе самого портала. Для этого нам нужно отредактировать jboss-portal.sar / portal-server.war / WEB-INF / web.xml и добавить определение сервлета и отображение сервлета:

    <servlet>
<servlet-name>localeServlet</servlet-name>
<servlet-class>org.jboss.portal.myPortal.servlet.LocaleServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>localeServlet</servlet-name>
<url-pattern>/locale</url-pattern>
</servlet-mapping>

Сервлет просто берет параметр, полученный из параметра GET, сохраняет его в сеансе как «org.jboss.portal.myPortal.locale» и перенаправляет пользователя туда, откуда он пришел:

package org.jboss.portal.extension.servlet;

import [...]

public class LocaleServlet extends HttpServlet {

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
{
String country = request.getParameter("country");
String language = request.getParameter("language");
Locale locale = new Locale(language, country);
request.getSession(true).setAttribute("org.jboss.portal.myPortal.locale", locale);
response.sendRedirect(request.getParameter("from"));
}
}

В макет мы добавили два изображения флага со ссылками на
сервлет : <a href=»<%= request.getAttribute(«org.jboss.portal.PORTAL_CONTEXT_PATH») %> / locale? Country = en & language = en & from = <% = request.getRequestURI ()%> «> <img src =» <% = request.getContextPath ()%> / images / flags / en.gif «alt =» английский «/> </a>
& nbsp;
<a href=»<%= request.getAttribute(«org.jboss.portal.PORTAL_CONTEXT_PATH») %> / locale? country = ch & language = fr & from = <% = request.getRequestURI ()%> «> <img src =» <% = request.getContextPath ()%> / images / flags / fr.gif «alt =» French «/> </a>

Теперь, чтобы заменить поведение по умолчанию для получения локали из сеанса вместо веб-браузера или профиля пользователя, нам нужно заменить перехватчик по умолчанию, определенный в jboss-portal.sar / META-INF / jboss-service.xml
Вместо этого MBean:

   <mbean code="org.jboss.portal.core.aspects.server.LocaleInterceptor"
name="portal:service=Interceptor,type=Server,name=Locale" xmbean-dd=""
xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean">
<xmbean/>
</mbean>

Мы создаем наш собственный org.jboss.portal.extension.aspect.LocaleInterceptor:

package org.jboss.portal.extension.aspect;

import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import org.jboss.portal.common.invocation.InvocationException;
import org.jboss.portal.server.ServerInterceptor;
import org.jboss.portal.server.ServerInvocation;
import org.jboss.portal.server.ServerRequest;

public class LocaleInterceptor extends ServerInterceptor {

protected void invoke(ServerInvocation invocation) throws Exception,
InvocationException {

HttpServletRequest request = invocation.getServerContext().getClientRequest();
Locale locale = (Locale)request.getSession().getAttribute("org.jboss.portal.myPortal.locale");

if (locale == null)
{
locale = Locale.ENGLISH;
}

ServerRequest req = invocation.getRequest();

// Set the locale for the request
Locale[] tmp = new Locale[]{locale};
req.setLocales(tmp);

// Invoke next interceptors
invocation.invokeNext();
}

}

Мы заменяем значение ядра MBean на наш новый класс и не забываем включить jar, включая этот класс, в jboss-portal.sar / lib.

Собираем все вместе

Все источники для этой демонстрации доступны в SVN:
http://anonsvn.jboss.org/repos/portal/other/dzone_article
. Файлы readme.txt объясняют, как настроить и запустить настроенный портал. При правильной настройке вы сможете пользоваться визуально настроенным порталом, используя декларативную безопасность и кэширование, с настраиваемым способом определения предпочтительного языка и новым веб-приложением, создающим контент для фрагмента страницы.