Ошибка переопределения user_action.jsp после обновления до Liferay 7.3

Мы внедрили модуль corejspook для настройки user_action.jsp в Liferay 7.0.6, и он отлично работал.

После обновления до Liferay 7.3.6 перестало работать. Я убедился, что модуль, на который мы заменяем jsp, правильный, выполнив поиск в оболочке gogo. Я также просмотрел исходный код, чтобы убедиться, что пакет, содержащий .jsp, правильный. И я обновил номер версии до версии комплекта Liferay 7.3 (5.0.53). Запись в моем bnd.bnd: Fragment-Host: com.liferay.users.admin.web;bundle-version=5.0.53

Когда я развертываю модуль, он не перезапускает пакет узла фрагмента, как должен (как это было в Liferay 7.0). Перезапуск этого пакета вручную также не работает — измененный .jsp не используется.

Кстати, у нас есть другие corejsphooks, которые отлично работают. Это единственное, что не работает, поэтому я должен что-то здесь упустить.

Обновление: я включаю код по запросу. Вот четыре файла в модуле (не считая файлов по умолчанию, таких как build.gradle и Language_en.properties, которые создаются при создании модуля) в модуле.

бнд.бнд

Bundle-Version: 7.3.6.1
Fragment-Host: com.liferay.users.admin.web;bundle-version="5.0.53"
-sources: true
-jsp: *.jsp,*.jspf

user_action.jsp

<%--
/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */
--%>

<%@ include file="/init.jsp" %>
 
<%@ page import="com.liferay.petra.encryptor.Encryptor" %>
<%@ page import="com.liferay.portal.kernel.util.HtmlUtil" %>

<%

UserSearch searchContainer = (UserSearch)request.getAttribute("liferay-ui:search:searchContainer");

String redirect = searchContainer.getIteratorURL().toString();

ResultRow row = (ResultRow)request.getAttribute(WebKeys.SEARCH_CONTAINER_RESULT_ROW);

User user2 = (User)row.getObject();

long userId = user2.getUserId();

String userLandingPage = null;

User currentUser = user2;
List<Organization> userOrganizations = currentUser.getOrganizations();


if (Validator.isNotNull(userOrganizations) && !userOrganizations.isEmpty())
{
    // If user is member of more than one organization then it will take
    // first organization from list
    Organization organization = userOrganizations.get(0);
    if (Validator.isNotNull(organization))
    {
        Group organizationGroup = organization.getGroup();
        if (organizationGroup.getPrivateLayoutsPageCount() > 0)
        {
            
            String privateGroupURL = PropsUtil.get(PropsKeys.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING);
            String groupFriendlyURL = organizationGroup.getFriendlyURL();
            userLandingPage = privateGroupURL + groupFriendlyURL;

            String encDoAsUserId = Encryptor.encrypt(
                company.getKeyObj(), String.valueOf(userId));
            
            userLandingPage = userLandingPage + "?doAsUserId=" + HtmlUtil.escapeURL(encDoAsUserId);
            System.out.println("userLandingPage is: " + userLandingPage);
        } 
        else
        {
            System.out.println(organizationGroup.getName() + " organization site doesn't have any private page. So default landing page will be used");
        }
    }
}

// System.out.println("Landing page is: " + userLandingPage);

 
%>

<liferay-ui:icon-menu
    direction="left-side"
    icon="<%= StringPool.BLANK %>"
    markupView="lexicon"
    message="<%= StringPool.BLANK %>"
    showWhenSingleIcon="<%= true %>"
>

    <%
    boolean hasUpdatePermission = UserPermissionUtil.contains(permissionChecker, userId, ActionKeys.UPDATE);
    %>

    <c:if test="<%= hasUpdatePermission %>">
        <portlet:renderURL var="editUserURL">
            <portlet:param name="mvcRenderCommandName" value="/users_admin/edit_user" />
            <portlet:param name="redirect" value="<%= redirect %>" />
            <portlet:param name="p_u_i_d" value="<%= String.valueOf(userId) %>" />
        </portlet:renderURL>

        <liferay-ui:icon
            message="edit"
            url="<%= editUserURL %>"
        />
    </c:if>

    <c:if test="<%= UserPermissionUtil.contains(permissionChecker, userId, ActionKeys.PERMISSIONS) %>">
        <liferay-security:permissionsURL
            modelResource="<%= User.class.getName() %>"
            modelResourceDescription="<%= user2.getFullName() %>"
            resourcePrimKey="<%= String.valueOf(userId) %>"
            var="permissionsUserURL"
            windowState="<%= LiferayWindowState.POP_UP.toString() %>"
        />

        <liferay-ui:icon
            message="permissions"
            method="get"
            url="<%= permissionsUserURL %>"
            useDialog="<%= true %>"
        />
    </c:if>

    <c:if test="<%= (PropsValues.LAYOUT_USER_PRIVATE_LAYOUTS_ENABLED || PropsValues.LAYOUT_USER_PUBLIC_LAYOUTS_ENABLED) && hasUpdatePermission %>">

        <%
        PortletURL managePagesURL = PortletProviderUtil.getPortletURL(request, user2.getGroup(), Layout.class.getName(), PortletProvider.Action.EDIT);

        managePagesURL.setParameter("redirect", redirect);
        %>

        <liferay-ui:icon
            message="manage-pages"
            url="<%= managePagesURL.toString() %>"
        />
    </c:if>

    <c:if test="<%= !PropsValues.PORTAL_JAAS_ENABLE && PropsValues.PORTAL_IMPERSONATION_ENABLE && (userId != user.getUserId()) && !themeDisplay.isImpersonated() && UserPermissionUtil.contains(permissionChecker, userId, ActionKeys.IMPERSONATE) %>">
        <liferay-security:doAsURL
            doAsUserId="<%= userId %>"
            var="impersonateUserURL"
        />

        <liferay-ui:icon
            message="impersonate-user"
            target="_blank"
            url="<%= Validator.isNotNull(userLandingPage) ? userLandingPage : impersonateUserURL %>"
        />
    </c:if>

    <c:if test="<%= UserPermissionUtil.contains(permissionChecker, userId, ActionKeys.DELETE) %>">
        <c:if test="<%= !user2.isActive() %>">
            <portlet:actionURL name="/users_admin/edit_user" var="restoreUserURL">
                <portlet:param name="<%= Constants.CMD %>" value="<%= Constants.RESTORE %>" />
                <portlet:param name="redirect" value="<%= redirect %>" />
                <portlet:param name="deleteUserIds" value="<%= String.valueOf(userId) %>" />
            </portlet:actionURL>

            <liferay-ui:icon
                message="activate"
                url="<%= restoreUserURL %>"
            />
        </c:if>

        <portlet:actionURL name="/users_admin/edit_user" var="deleteUserURL">
            <portlet:param name="<%= Constants.CMD %>" value="<%= user2.isActive() ? Constants.DEACTIVATE : Constants.DELETE %>" />
            <portlet:param name="redirect" value="<%= redirect %>" />
            <portlet:param name="deleteUserIds" value="<%= String.valueOf(userId) %>" />
        </portlet:actionURL>

        <c:if test="<%= userId != user.getUserId() %>">
            <c:choose>
                <c:when test="<%= user2.isActive() %>">
                    <liferay-ui:icon-deactivate
                        url="<%= deleteUserURL %>"
                    />
                </c:when>
                <c:when test="<%= !user2.isActive() && PropsValues.USERS_DELETE %>">
                    <liferay-ui:icon-delete
                        url="<%= deleteUserURL %>"
                    />
                </c:when>
            </c:choose>
        </c:if>
    </c:if>

</liferay-ui:icon-menu>

corejspook.UserActionCustomJspBag.java

/**
 * Copyright 2000-present Liferay, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package corejsphook;

import com.liferay.portal.deploy.hot.CustomJspBag;
import com.liferay.portal.kernel.url.URLContainer;

import java.net.URL;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;

/**
 * @author Scott McIntosh, ICF
 */
@Component(
    immediate = true,
    property = {
        "context.id=UserActionCustomJspBag",
        "context.name=User Action Custom JSP Bag",
        "service.ranking:Integer=111"
    }
)
public class UserActionCustomJspBag implements CustomJspBag 
{
    @Override
    public String getCustomJspDir() {
        return "META-INF/resources/";
    }

    @Override
    public List<String> getCustomJsps() {
        System.out.println("In getCustomJsps().  _customJsps is null?");
        System.out.println(_customJsps == null);
        return _customJsps;
    }

    @Override
    public URLContainer getURLContainer() {
        System.out.println("In getURLContainer()");
        return _urlContainer;
    }

    @Override
    public boolean isCustomJspGlobal() {
        System.out.println("In isCustomJspGlobal()");
        return true;
    }

    @Activate
    protected void activate(BundleContext bundleContext) {
        System.out.println("In activate()");
        bundle = bundleContext.getBundle();

        _customJsps = new ArrayList<>();

        Enumeration<URL> entries = bundle.findEntries(
            getCustomJspDir(), "*.jsp", true);

        while (entries.hasMoreElements()) {
            URL url = entries.nextElement();
            System.out.println("Processing jsp: " + url);
            _customJsps.add(url.getPath());
        }
    }

    private List<String> _customJsps;

    private final URLContainer _urlContainer = new URLContainer() {

        @Override
        public Set<String> getResources(String path) {
            System.out.println("In getResources()");
            Set<String> paths = new HashSet<>();

            for (String entry : _customJsps) {
                if (entry.startsWith(path)) {
                    paths.add(entry);
                }
            }

            return paths;
        }

        @Override
        public URL getResource(String name) {
            System.out.println("In getResource()");
            return bundle.getEntry(name);
        }

    };

    private Bundle bundle;

}

gov.nysdot.rideshare.NYRideshareEnUsResourceBundle.java

ackage gov.nysdot.rideshare;

import com.liferay.portal.kernel.language.UTF8Control;

import java.util.Enumeration;
import java.util.ResourceBundle;
import org.osgi.service.component.annotations.Component;

@Component(
        property = { "language.id=en_US" }, 
        service = ResourceBundle.class
    )
    public class NYRideshareEnUsResourceBundle extends ResourceBundle {

        @Override
        protected Object handleGetObject(String key) {
            return _resourceBundle.getObject(key);
        }

        @Override
        public Enumeration<String> getKeys() {
            return _resourceBundle.getKeys();
        }

        private final ResourceBundle _resourceBundle = ResourceBundle.getBundle(
            "content.Language_en_US", UTF8Control.INSTANCE);

    }

Обновление: я начал с нуля, но получаю тот же результат. Я создал новый модуль, используя:

$ blade create -t fragment gov.nysdot.user-action-hook --host-bundle-symbolic-name com.liferay.users.admin.web --host-bundle-version 5.0.53

Затем я скопировал user_action.jsp из исходного кода (/modules/apps/users-admin/users-admin-web/src/main/resources/META-INF/resources/user_action.jsp).

Для проверки я просто продублировал разделительную линию в строке 156 (), чтобы иметь визуальную подсказку. Если бы переопределение сработало, я бы увидел две разделительные линии.

Я построил с помощью «grade build» и развернул на своем сервере. Пакет com.liferay.users.admin.web не перезапускался, и изменений не было.

Теперь изменений от того, что создал скрипт создания модуля, практически нет.


person Scott McIntosh    schedule 11.06.2021    source источник
comment
пожалуйста, покажите код, желательно минимально воспроизводимый пример   -  person Olaf Kock    schedule 12.06.2021
comment
@OlafKock Я обновил вопрос с кодом модуля. Спасибо!   -  person Scott McIntosh    schedule 16.06.2021


Ответы (1)


Что меня поражает в вашем коде/описании:

  • JSP - это jsp модуля, а не основной jsp. Таким образом, я бы не ожидал CustomJspBag, а скорее следовал бы module_jsp_override
  • Пакет фрагментов никогда не будет АКТИВНЫМ, а только РАЗРЕШЕННЫМ (как в жизненных циклах пакетов OSGi). Таким образом, он может доставлять файлы, которые переопределяют файлы хост-пакета, но не собственный код. Вы предоставляете отдельные услуги, которые точно не будут доступны и запущены — они должны жить в других пакетах. Считайте связку фрагментов пассивной.

Таким образом, не превращая ваши файлы в проект, я бы предположил, что это проблема.

Преобразуйте пакет в проект module-jsp-override (без java-кода, обратите внимание на bnd.bnd). Убедитесь, что JSP по-прежнему такой, каким должен быть: вы не можете просто скопировать JSP 7.0 в 7.3 и предположить, что эти изменения по-прежнему точно реализуют то, что вам нужно. Скорее, вам понадобится трехстороннее слияние между стандартной версией 7.0, вашими модификациями и стандартной версией 7.3 jsp.

person Olaf Kock    schedule 18.06.2021
comment
Спасибо за этот совет. Я начал с нуля, но я получаю тот же результат. - person Scott McIntosh; 22.06.2021
comment
Я обновил свой вопрос новыми шагами, которые я предпринял для создания переопределения модуля. - person Scott McIntosh; 22.06.2021