Skip to content

Commit

Permalink
Support for Liferay 7.2 and 7.3
Browse files Browse the repository at this point in the history
There are some failing tests, but this is in a feature branch for now so it should be fine.
  • Loading branch information
caalador authored Dec 3, 2020
1 parent 7724e0d commit 7a8521c
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 54 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
<maven.clean.plugin.version>3.0.0</maven.clean.plugin.version>

<testbench.version>6.2.0</testbench.version>
<flow.version>2.2-SNAPSHOT</flow.version>
<flow.version>2.4-SNAPSHOT</flow.version>
<flow.cdi.version>11.2-SNAPSHOT</flow.cdi.version>
<jetty.version>9.4.9.v20180320</jetty.version>

Expand Down
2 changes: 0 additions & 2 deletions vaadin-portlet/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
<scope>provided</scope>
</dependency>


<!--Portlet API -->
<dependency>
<groupId>javax.portlet</groupId>
Expand Down Expand Up @@ -108,4 +107,3 @@
</plugins>
</build>
</project>

Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ void init() {
* parameters to add to event action
*/
public void fireEvent(String eventName, Map<String, String> parameters) {
checkPortletHubAvailability();
checkPortletHubRequired();
executeJS(getFireEventScript(eventName, parameters));
}

Expand Down Expand Up @@ -340,7 +340,7 @@ void updateModeAndState(PortletMode portletMode, WindowState windowState) {

private Registration doAddEventChangeListener(String eventType,
PortletEventListener listener) {
checkPortletHubAvailability();
checkPortletHubRequired();
String uid = Long.toString(nextUid.getAndIncrement());
String namespace = registerEventChangeListener(uid, eventType,
listener);
Expand Down Expand Up @@ -423,7 +423,7 @@ private void executeJS(String script, Serializable... params) {
}
}

private void checkPortletHubAvailability() {
private void checkPortletHubRequired() {
if (!isPortlet3.get()) {
String message = "Portlet Hub not available; to use Vaadin "
+ "Portlet IPC, ensure that portlet.xml specifies at "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.vaadin.flow.portal;

import java.io.IOException;

import javax.portlet.HeaderRequest;
import javax.portlet.HeaderResponse;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import com.vaadin.flow.component.Component;

/**
* VaadinPortlet workarounds for Liferay versions 7.2.x and 7.3.x
*
* Requires the implementing portlet to signal PortletHub dependency due to a Liferay bug.
* Addresses inconsistent behaviour in injecting required Vaadin specific javascript.
*/
public abstract class VaadinLiferayPortlet<C extends Component>
extends VaadinPortlet<C> {

@Override
public void renderHeaders(HeaderRequest request, HeaderResponse response) {
// Skip most of renderHeaders for liferay portlets as it is called inconsistently between different versions (7.2, 7.3).
// - response.addDependency() won't work (ref: https://issues.liferay.com/browse/LPS-107438).
// - injected scripts may or may not actually appear on the page, and they are processed as XML (?)
// -> do the injection in doHeaders instead

// Calling this probably won't help (see above)
response.addDependency("PortletHub", "javax.portlet", "3.0.0");
}

@Override
protected void doHeaders(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
if (!checkStaticResourcesConfiguration()) {
throw new PortletException(
"Unexpected static resources path for Vaadin Liferay Portlet");
}

super.doHeaders(request, response);

/**
* FIXME: This is pretty quaranteed to end up on the page, however...
* 1. The script tag will appear once per portlet
* 2. Liferay partial page update breaks the page and causes Vaadin components to render blank
* *if* the browser has stale Vaadin related things from the previous page.
*
* In other words we probably need a surgical way to scrub stale Vaadin things from users browser
* that only runs once, even if the script can be on the page multiple times. Alternatively we can
* just detect the problem and force a hard reload.
*/
response.getWriter().println(
getPortletScriptTag(request, "scripts/PortletMethods.js"));

// we don't actually know if the portlet is a 3.0 one here, but we need to stop the IPC errors from being thrown
// with liferay 7.3 the portlet generally fails to render if the exception is thrown
isPortlet3.set(true);
}

private boolean checkStaticResourcesConfiguration() {
return getStaticResourcesPath().startsWith("/o/");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
*/
package com.vaadin.flow.portal;

import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
Expand All @@ -33,24 +40,13 @@
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.WindowState;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.WebComponentExporter;
import com.vaadin.flow.component.WebComponentExporterFactory;
import com.vaadin.flow.component.page.Push;
import com.vaadin.flow.component.webcomponent.WebComponent;
import com.vaadin.flow.function.DeploymentConfiguration;
import com.vaadin.flow.function.SerializableRunnable;
Expand All @@ -65,8 +61,12 @@
import com.vaadin.flow.server.VaadinConfigurationException;
import com.vaadin.flow.server.VaadinService;
import com.vaadin.flow.server.VaadinSession;
import com.vaadin.flow.shared.communication.PushMode;
import com.vaadin.flow.shared.util.SharedUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Vaadin implementation of the {@link GenericPortlet}.
*
Expand All @@ -83,11 +83,10 @@ public abstract class VaadinPortlet<C extends Component> extends GenericPortlet
private static final String DEV_MODE_ERROR_MESSAGE = "<h2>⚠️Vaadin Portlet does not work in development mode running webpack-dev-server</h2>"
+ "<p>To run a portlet in development mode, you need to activate both <code>prepare-frontend</code> and <code>build-frontend</code> goals of <code>vaadin-maven-plugin</code>. "
+ "To run a portlet in production mode see <a href='https://vaadin.com/docs/v14/flow/production/tutorial-production-mode-basic.html' target='_blank'>this</a>.</p>";
public static final String PORTLET_SCRIPTS = "general-methods";

private VaadinPortletService vaadinService;

private AtomicBoolean isPortlet3 = new AtomicBoolean();
protected AtomicBoolean isPortlet3 = new AtomicBoolean();

// @formatter:off
/*
Expand Down Expand Up @@ -148,6 +147,7 @@ public abstract class VaadinPortlet<C extends Component> extends GenericPortlet
*
*/
@PreserveOnRefresh
@Push(PushMode.DISABLED)
protected class PortletWebComponentExporter
extends WebComponentExporter<C> {
/**
Expand Down Expand Up @@ -235,39 +235,37 @@ protected void portletInitialized() throws PortletException {
public void renderHeaders(HeaderRequest request, HeaderResponse response)
throws PortletException, IOException {
// This is only called for portlet 3.0 portlets.
// NOTE: Liferay 7.3.x seems to not call this for VaadinPortlets
isPortlet3.set(true);
response.addDependency("PortletHub", "javax.portlet", "3.0.0");

// How do we get this to only exec once for multiple portlets on same
// page, but still every time the page refreshes?
String initScript = (String) request.getPortletContext()
.getAttribute(PORTLET_SCRIPTS);
if (initScript == null) {
initScript = "<script type=\"text/javascript\">"
+ loadFile("scripts/PortletMethods.js") + "</script>";
request.getPortletContext().setAttribute(PORTLET_SCRIPTS,
initScript);
}
response.getWriter().println(initScript);
response.getWriter().println(
getPortletScriptTag(request, "scripts/PortletMethods.js"));
}

private String loadFile(String fileName) {
String fileContent = "";
InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream(fileName);
if (inputStream == null) {
LoggerFactory.getLogger(getClass())
.warn("No resource file found for '{}'", fileName);
return fileContent;
}
protected String getPortletScriptTag(RenderRequest request,
String filePath) {
// static bundle or context path?
// latter is more lenient for old projects, former is less friendly to caching
String scriptSrc = getServerUrl(request) + getStaticResourcesPath()
+ filePath;
return "<script src=\"" + scriptSrc + "\" type=\"text/javascript\" />";
}

try {
fileContent = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
} catch (IOException e) {
LoggerFactory.getLogger(getClass())
.error("Failed to load file '{}'", fileName, e);
}
return fileContent;
protected String getStaticResourcesPath() {
return getService().getDeploymentConfiguration().getStringProperty(
PortletConstants.PORTLET_PARAMETER_STATIC_RESOURCES_MAPPING,
"/vaadin-portlet-static/");
}

private static String getServerUrl(RenderRequest req) {
int port = req.getServerPort();
String scheme = req.getScheme();
boolean isDefaultPort = (scheme == "http" && port == 80)
|| (scheme == "https" && port == 443);

return String.format("%s://%s%s", scheme, req.getServerName(),
(isDefaultPort ? "" : ":" + port));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//<![CDATA[
// Liferay parses this file as XML, so make it appear as a CDATA section
window.Vaadin = window.Vaadin || {};
window.Vaadin.Flow = window.Vaadin.Flow || {};
// <liferay>
Expand All @@ -14,12 +16,12 @@ if (!window.Vaadin.Flow.Portlets) {

window.Vaadin.Flow.Portlets = {};

window.Vaadin.Flow.Portlets.reload = function (hub) {
window.Vaadin.Flow.Portlets.executeWhenHubIdle = function (hub, task) {
var poller = function () {
if (hub.isInProgress()) {
setTimeout(poller, 10);
} else {
location.reload();
task(hub);
}
};
poller();
Expand All @@ -32,12 +34,17 @@ if (!window.Vaadin.Flow.Portlets) {
window.Vaadin.Flow.Portlets.setPortletState = function (portletRegistryName, windowState, portletMode) {
var hub = window.Vaadin.Flow.Portlets.getHubRegistartion(portletRegistryName);

var state = hub.newState();
state.windowState = windowState;
state.portletMode = portletMode;
hub.setRenderState(state);
window.Vaadin.Flow.Portlets.executeWhenHubIdle(hub, function(hub) {
var state = hub.newState();
state.windowState = windowState;
state.portletMode = portletMode;
hub.setRenderState(state);

window.Vaadin.Flow.Portlets.reload(hub);
// FIXME: the addressbook demo was created while the reloading on state change did not happen
// fix the demo or don't reload here, in the interest of time latter it is for now.
// This behaviour makes no sense with multi portlet pages anyways. -> make optional?
//window.Vaadin.Flow.Portlets.executeWhenHubIdle(hub, function (hub) { location.reload() });
});
}

window.Vaadin.Flow.Portlets.fireEvent = function (portletRegistryName, event, parameters) {
Expand All @@ -59,6 +66,9 @@ if (!window.Vaadin.Flow.Portlets) {
window.portlet.data.pageRenderState.portlets[portletRegistryName].allowedPM = portletModes;
window.portlet.data.pageRenderState.portlets[portletRegistryName].allowedWS = windowStates;
window.portlet.data.pageRenderState.portlets[portletRegistryName].encodedActionURL = encodeURIComponent(actionUrl);
// liferay 7.3 does not always check if the renderData is there
window.portlet.data.pageRenderState.portlets[portletRegistryName].renderData =
window.portlet.data.pageRenderState.portlets[portletRegistryName].renderData || { content: null, mimeType: "text/html" };
// </liferay>
customElements.whenDefined(tag).then(function () {
var elem = document.querySelector(tag);
Expand Down Expand Up @@ -185,3 +195,4 @@ if (!window.Vaadin.Flow.Portlets) {
}
};
}
//]]>
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ protected Stream<String> getExcludedPatterns() {
// serializable
"com\\.vaadin\\.flow\\.portal\\." +
"PortletStreamReceiverHandler\\$StreamRequestContext",
"com\\.vaadin\\.flow\\.portal\\.VaadinHttpAndPortletRequest",
"com\\.vaadin\\.flow\\.portal\\.VaadinHttpPortletRequest",
"com\\.vaadin\\.flow\\.portal\\.VaadinLiferayRequest"
);
Expand Down

0 comments on commit 7a8521c

Please sign in to comment.