Как создать модульное приложение JSF 2.0?

У меня есть приложение с четко определенным интерфейсом. Он использует CDI для разрешения модулей, (в частности, он использует экземпляры инстанции для интерфейсов API для решения модулей) и без проблем передает различные данные назад и четвертый через интерфейсы. Я намеренно сохранил API и реализацию отдельно, и модули только наследуют от API, чтобы избежать жесткой связи, и приложение знает только о модулях через ожидания выполнения, а передача данных выполняется через API. Приложение отлично работает без модулей, которые можно добавить просто, отбросив банку в папку WEB-INF/lib и перезапустив сервер приложений.

В тех случаях, когда я сталкиваюсь с проблемами, я хочу, чтобы модули создавали часть представления, и поэтому я хочу вызывать переносимым образом как компонент JSF, так и сделать его из модуля в порядке чтобы он сделал свое мнение. Я уже решил, какой модуль я хочу вызывать, и имею ссылки на интерфейс модуля. То, как я изначально думал, чтобы сделать это, было сделать ui: include, который просит модуль предоставить, где он просматривает шаблон, но я понятия не имею, как ответить на этот запрос значимым образом, поскольку разрешение представления выполняется из приложения root, а не корень библиотеки.

Резюме состоит в том, что я не знаю, как перераспределить пробел от приложения к библиотеке, используя JSF для файлов .xhtml(template/component).

Использование CC было бы неплохо, но как я могу указать, что я хочу, чтобы конкретный экземпляр CC во время выполнения вместо того, чтобы иметь жесткую кодировку на странице?

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

Я бы предпочел избегать принуждения разработчиков модулей к возможности использования UIComponent с большой нагрузкой, если это возможно, что означает либо динамический способ выполнения ui: include (или некоторый эквивалент), либо динамический способ вызова CC. (Я не против кодирования UIComponent подхода ONCE в приложении, если это то, что требуется, чтобы сделать жизнь разработчиков модулей проще)

Любые предложения о том, где я должен посмотреть, чтобы понять это? (Я отправлю ответ здесь, если найду его первым)

Ответ 1

Я понимаю, что ваш вопрос в основном сводится к тому, как включить отображение Facelets в JAR?

Вы можете сделать это, разместив в JAR пользовательский ResourceResolver.

public class FaceletsResourceResolver extends ResourceResolver {

    private ResourceResolver parent;
    private String basePath;

    public FaceletsResourceResolver(ResourceResolver parent) {
        this.parent = parent;
        this.basePath = "/META-INF/resources"; // TODO: Make configureable?
    }

    @Override
    public URL resolveUrl(String path) {
        URL url = parent.resolveUrl(path); // Resolves from WAR.

        if (url == null) {
            url = getClass().getResource(basePath + path); // Resolves from JAR.
        }

        return url;
    }

}

Настройте это в webapp web.xml следующим образом:

<context-param>
    <param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
    <param-value>com.example.FaceletsResourceResolver</param-value>
</context-param>

Представьте, что у вас есть /META-INF/resources/foo/bar.xhtml в random.jar, тогда вы можете просто включить его обычным способом

<ui:include src="/foo/bar.xhtml" />

или даже динамически

<ui:include src="#{bean.path}" />

Примечание. Начиная с версии Servlet 3.0 и более поздних версий JBoss/JSF 2.0, весь метод ResourceResolver не требуется, если вы храните файлы в папке /META-INF/resources. Вышеприведенный ResourceResolver является обязательным только для версий Servlet 2.5 или старше JBoss/JSF, поскольку они имеют ошибки в разрешении ресурсов META-INF.

См. также:

Ответ 3

Кстати, вы можете избежать реализации собственного распознавателя ресурсов, когда используете припой для пайки (в настоящее время интегрированный в apache deltaspike), который является действительно полезной библиотекой, дополняющей CDI (ваша типичная модель Java EE 6)

Я тоже экспериментировал с модулями в приложениях jsf. В основном я построил интерфейс шаблона с панелью инструментов, которая заполняется кнопками, предоставляемыми каждым модулем. Как правило, вы сделаете это, предоставив список строк в качестве именованного объекта:

@Produces
@SomethingScoped
@Named("topMenuItems")
public List<String> getTopMenuItems(){
return Arrays.asList("/button1.xhtml", "/button2.xhtml", "/button3.xhtml");
}

Обратите внимание, как каждая из кнопок может поступать из другого модуля приложения jsf. Интерфейс шаблона содержит панель, в которой

вы можете использовать его в своей разметке следующим образом (на свой страх и риск;)):

....
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
....
<xy:toolbar>
  <xy:toolbarGroup>
    <c:forEach items="#{topMenuItems}" var="link">
      <ui:include src="#{link}" />
    </c:forEach>
  </xy:toolbarGroup>
</xy:toolbar>
<xy:panel>
  <ui:include src="#{contentPath}"/>
</xy:panel>

Это была панель инструментов и панель содержимого.

простая кнопка или определение представления может выглядеть так:

<ui:composition ...>
    <xy:commandButton actionListener="#{topMenuController.switchContent()}"
        value="Test" id="testbutton" />
</ui:composition>

позволяет назвать этот артефакт view1.xhtml

Когда эта кнопка нажата (которая не вызывает обратную передачу с помощью actionListener, мы хотим перезагрузить контент с помощью ajax), switchContentMethod в вашем контроллере может изменить строку, возвращаемую getContentPath:

public void switchContent(){
    contentPath = "/view1.xhtml";
}

@Produces
@SomethingScoped
@Named("contentPath")
public String getContentPath(){
    return contentPath;
}

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

Некоторые советы (или "что я узнал" ):

  • Вы можете выбрать большую область для метода getTopMenuItems.
  • Не вставляйте тег ui: include. К сожалению, это невозможно (например, ваш view1.xhtml не может содержать другую композицию). я действительно хотелось бы, чтобы подобное было возможно, поскольку вы можете модульные представления jsf с этим, вроде портлетов только без портлеты.. = D
  • Выполнение ui: включение в компоненты контейнера, такие как tabviews, также оказывается проблематичным.
  • Обычно не рекомендуется смешивать JSTL (c: forEach) и JSF. Тем не менее, я нашел, что это единственный способ работать как ui: repeat получает оценивается слишком поздно, например. ваш включенный контент не отображается.