Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Liferay feature branch to master #196

Merged
merged 19 commits into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-parent</artifactId>
<version>2.0.1</version>
<version>2.0.2</version>
</parent>

<modules>
Expand Down
6 changes: 2 additions & 4 deletions vaadin-portlet/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,18 @@
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>license-checker</artifactId>
<version>1.0.0</version>
<version>1.2.1</version>
<scope>compile</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/com.liferay.portal/com.liferay.portal.kernel -->
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>com.liferay.portal.kernel</artifactId>
<version>4.38.0</version>
<version>9.30.0</version>
<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 @@ -23,6 +23,8 @@

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.stream.Collectors;

import com.vaadin.flow.function.DeploymentConfiguration;
import com.vaadin.flow.server.SynchronizedRequestHandler;
Expand Down Expand Up @@ -90,12 +92,24 @@ public boolean synchronizedHandleRequest(VaadinSession session,
// message will be shown in the browser).
// There is also a license check when the UI is going to be
// instantiated. That will throw a server side exception.
LicenseChecker.checkLicense(VaadinPortletService.PROJECT_NAME,
VaadinPortletService.getPortletVersion());
LicenseChecker.checkLicense(VaadinPortletService.PROJECT_NAME,
VaadinPortletService.getPortletVersion());
}
String initScript = String.format(
"<script>window.Vaadin.Flow.Portlets.registerElement('%s','%s');</script>",
tag, namespace);
String initScript = String
.format("<script>window.Vaadin.Flow.Portlets.registerElement('%s','%s','%s','%s','%s');</script>",
tag, namespace, Collections
.list(portlet.getWindowStates("text/html"))
.stream()
.map(state -> "\"" + state.toString()
+ "\"")
.collect(Collectors.joining(",", "[", "]")),
Collections
.list(portlet.getPortletModes("text/html"))
.stream()
.map(mode -> "\"" + mode.toString() + "\"")
.collect(Collectors.joining(",", "[", "]")),
((RenderResponse) resp).createActionURL());
// For liferay send accepted window states, portlet modes and action url to add to client side data.

writer.write(initScript);
writer.write("<" + tag + " data-portlet-id='" + namespace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,26 @@
*/
package com.vaadin.flow.portal;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

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

import com.vaadin.flow.server.AbstractStreamResource;
import com.vaadin.flow.server.StreamReceiver;
import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.server.VaadinRequest;
import com.vaadin.flow.server.VaadinResponse;
import com.vaadin.flow.server.VaadinSession;
import com.vaadin.flow.server.communication.StreamReceiverHandler;
import com.vaadin.flow.server.communication.StreamRequestHandler;

/**
Expand All @@ -26,7 +46,119 @@
* @since
*/
class PortletStreamRequestHandler extends StreamRequestHandler {

private static final char PATH_SEPARATOR = '/';

private final PortletStreamResourceHandler resourceHandler = new PortletStreamResourceHandler();
private StreamReceiverHandler receiverHandler;

public PortletStreamRequestHandler() {
super(new PortletStreamReceiverHandler());
this(new PortletStreamReceiverHandler());
}

protected PortletStreamRequestHandler(
StreamReceiverHandler receiverHandler) {
super(receiverHandler);
this.receiverHandler = receiverHandler;
}

@Override
public boolean handleRequest(VaadinSession session, VaadinRequest request,
VaadinResponse response) throws IOException {

String pathInfo = request.getPathInfo();
if (pathInfo == null) {
return false;
}
// remove leading '/'
assert pathInfo.startsWith(Character.toString(PATH_SEPARATOR));
pathInfo = pathInfo.substring(1);

if (!pathInfo.startsWith(DYN_RES_PREFIX)) {
return false;
}

Optional<AbstractStreamResource> abstractStreamResource;
session.lock();
try {
abstractStreamResource = PortletStreamRequestHandler
.getPathUri(pathInfo)
.flatMap(session.getResourceRegistry()::getResource);
if (!abstractStreamResource.isPresent()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
"Resource is not found for path=" + pathInfo);
return true;
}
} finally {
session.unlock();
}

if (abstractStreamResource.isPresent()) {
AbstractStreamResource resource = abstractStreamResource.get();
if (resource instanceof StreamResource) {
resourceHandler.handleRequest(session, request, response,
(StreamResource) resource);
} else if (resource instanceof StreamReceiver) {
StreamReceiver streamReceiver = (StreamReceiver) resource;
String[] parts = parsePortletPath(pathInfo);

receiverHandler.handleRequest(session, request, response,
streamReceiver, parts[0], parts[1]);
} else {
getLogger().warn("Received unknown stream resource.");
}
}
return true;
}

/**
* Parse the pathInfo for id data.
* <p>
* URI pattern: VAADIN/dynamic/resource/[UIID]/[SECKEY]/[NAME]
*
* @see #generateURI
*/
private String[] parsePortletPath(String pathInfo) {
// strip away part until the data we are interested starts
int startOfData = pathInfo.indexOf(DYN_RES_PREFIX)
+ DYN_RES_PREFIX.length();

String uppUri = pathInfo.substring(startOfData);
// [0] UIid, [1] security key, [2] name
return uppUri.split("/", 3);
}

private static String encodeString(String name)
throws UnsupportedEncodingException {
return URLEncoder.encode(name, StandardCharsets.UTF_8.name())
.replace("+", "%20");
}

private static Optional<URI> getPathUri(String path) {
int index = path.lastIndexOf('/');
boolean hasPrefix = index >= 0;
if (!hasPrefix) {
getLogger().info("Unsupported path structure, path={}", path);
return Optional.empty();
}
String prefix = path.substring(0, index + 1);
String name = path.substring(prefix.length());
try {
URI uri = new URI(prefix + encodeString(name));
return Optional.of(uri);
} catch (UnsupportedEncodingException e) {
// UTF8 has to be supported
throw new RuntimeException(e);
} catch (URISyntaxException e) {
getLogger().info(
"Path '{}' is not correct URI (it violates RFC 2396)", path,
e);
return Optional.empty();
}
}

private static Logger getLogger() {
return LoggerFactory
.getLogger(PortletStreamRequestHandler.class.getName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.vaadin.flow.portal;

import javax.portlet.PortletContext;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Optional;

import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.server.StreamResourceWriter;
import com.vaadin.flow.server.VaadinRequest;
import com.vaadin.flow.server.VaadinResponse;
import com.vaadin.flow.server.VaadinSession;
import com.vaadin.flow.server.communication.StreamResourceHandler;

public class PortletStreamResourceHandler extends StreamResourceHandler {

@Override
public void handleRequest(VaadinSession session, VaadinRequest request,
VaadinResponse response, StreamResource streamResource)
throws IOException {
StreamResourceWriter writer;
session.lock();
try {
setResponseContentType(request, response, streamResource);
response.setCacheTime(streamResource.getCacheTime());
writer = streamResource.getWriter();
if (writer == null) {
throw new IOException(
"Stream resource produces null input stream");
}
} catch (Exception exception) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
throw exception;

} finally {
session.unlock();
}
// don't use here "try resource" syntax sugar because in case there is
// an exception the {@code outputStream} will be closed before "catch"
// block which sets the status code and this code will not have any
// effect being called after closing the stream (see #8740).
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
writer.accept(outputStream, session);
} catch (Exception exception) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
throw exception;
} finally {
if (outputStream != null) {
outputStream.close();
}
}
}

private void setResponseContentType(VaadinRequest request,
VaadinResponse response,
StreamResource streamResource) {
PortletContext context = ((VaadinPortletRequest) request)
.getPortletContext();
try {
response.setContentType(streamResource.getContentTypeResolver()
.apply(streamResource, null));
} catch (NullPointerException e) {
response.setContentType(Optional
.ofNullable(
context.getMimeType(streamResource.getName()))
.orElse("application/octet-stream"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.portlet.ResourceURL;

import com.vaadin.flow.server.AbstractStreamResource;
import com.vaadin.flow.server.StreamRegistration;
import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.server.StreamResourceRegistry;

Expand All @@ -49,6 +50,45 @@ public PortletStreamResourceRegistry(VaadinPortletSession session) {

@Override
public URI getTargetURI(AbstractStreamResource resource) {
return doGetUri(resource);
}

@Override
public StreamRegistration registerResource(AbstractStreamResource resource) {
StreamRegistration streamRegistration = super.registerResource(resource);
return new RegistrationWrapper(streamRegistration);
}

/**
* StreamRegistration implementation which embeds dynamic resource url
* into portlet url as a 'resourceUrl' query parameter, see
* {@link ResourceURL}.
*/
private final class RegistrationWrapper implements StreamRegistration {

private final StreamRegistration delegate;

public RegistrationWrapper(StreamRegistration streamRegistration) {
delegate = streamRegistration;
}

@Override
public URI getResourceUri() {
return doGetUri(getResource());
}

@Override
public void unregister() {
delegate.unregister();
}

@Override
public AbstractStreamResource getResource() {
return delegate.getResource();
}
}

private URI doGetUri(AbstractStreamResource resource) {
PortletResponse response = VaadinPortletService.getCurrentResponse()
.getPortletResponse();
if (response instanceof MimeResponse) {
Expand Down
Loading