Skip to content

Commit

Permalink
Make a workaround for Spring boot run as jar (#8808)
Browse files Browse the repository at this point in the history
* Make a workaround for Spring boot run as jar

Fixes #8705

* Add a unit test for implemented workaround.

* Add forgotten resource

* Improve variable name and add comments

(cherry picked from commit 6f1d6a5)
  • Loading branch information
Denis authored and mshabarov committed Aug 12, 2020
1 parent c21f8ff commit 9d31fe6
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 8 deletions.
35 changes: 27 additions & 8 deletions flow-server/src/main/java/com/vaadin/flow/server/PwaRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,21 @@
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.UncheckedIOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.vaadin.flow.server.frontend.FrontendUtils;
import org.slf4j.LoggerFactory;

import com.vaadin.flow.server.startup.ApplicationRouteRegistry;

import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonObject;
import org.slf4j.LoggerFactory;

/**
* Registry for PWA data.
Expand All @@ -56,6 +57,8 @@
* @since 1.2
*/
public class PwaRegistry implements Serializable {

private static final String META_INF_RESOURCES = "/META-INF/resources";
private static final String HEADLESS_PROPERTY = "java.awt.headless";
private static final String APPLE_STARTUP_IMAGE = "apple-touch-startup-image";
private static final String APPLE_IMAGE_MEDIA = "(device-width: %dpx) and (device-height: %dpx) "
Expand Down Expand Up @@ -84,18 +87,21 @@ private PwaRegistry(PWA pwa, ServletContext servletContext)

// Build pwa elements only if they are enabled
if (pwaConfiguration.isEnabled()) {
URL logo = servletContext
.getResource(pwaConfiguration.relIconPath());
URL offlinePage = servletContext
.getResource(pwaConfiguration.relOfflinePath());
URL logo = getResourceUrl(servletContext,
pwaConfiguration.relIconPath());

URL offlinePage = getResourceUrl(servletContext,
pwaConfiguration.relOfflinePath());
// Load base logo from servlet context if available
// fall back to local image if unavailable
BufferedImage baseImage = getBaseImage(logo);

if (baseImage == null) {
LoggerFactory.getLogger(PwaRegistry.class).error("Image is not found or can't be loaded: " + logo);
LoggerFactory.getLogger(PwaRegistry.class).error(
"Image is not found or can't be loaded: " + logo);
} else {
// Pick top-left pixel as fill color if needed for image resizing
// Pick top-left pixel as fill color if needed for image
// resizing
int bgColor = baseImage.getRGB(0, 0);

// initialize icons
Expand All @@ -118,6 +124,19 @@ private PwaRegistry(PWA pwa, ServletContext servletContext)
}
}

private URL getResourceUrl(ServletContext context, String path)
throws MalformedURLException {
URL resourceUrl = context.getResource(path);
if (resourceUrl == null) {
// this is a workaround specific for Spring default static resources
// location: see #8705
String cpPath = path.startsWith("/") ? META_INF_RESOURCES + path
: META_INF_RESOURCES + "/" + path;
resourceUrl = PwaRegistry.class.getResource(cpPath);
}
return resourceUrl;
}

private List<PwaIcon> initializeIcons(BufferedImage baseImage,
int bgColor) {
for (PwaIcon icon : getIconTemplates(pwaConfiguration.getIconPath())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2000-2020 Vaadin Ltd.
*
* 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 com.vaadin.flow.server;

import javax.servlet.ServletContext;

import java.io.ByteArrayOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

@PWA(name = "foo", shortName = "bar")
public class PwaRegistryTest {

@Test
public void pwaIconIsGeneratedBasedOnClasspathIcon_servletContextHasNoResources() {
ServletContext context = Mockito.mock(ServletContext.class);
// PWA annotation has default value for "iconPath" but servlet context
// has no resource for that path, in that case the ClassPath URL will be
// checked which is "META-INF/resources/icons/icon.png" (this path
// available is in the test resources folder). The icon in this path
// differs from the default icon and set of icons will be generated
// based on it
PwaRegistry registry = null;
try {
// Reflection is used here, because PwaRegistry has a private
// constructor and the 'getInstance' method is really hard to
// mocked up, it requires an access to
// 'ApplicationRouteRegistryWrapper', which is protected and
// invisible here.
registry = createPwaRegistryInstance(
PwaRegistryTest.class.getAnnotation(PWA.class), context);
} catch (Exception e) {
Assert.fail("Failed to create an instance of PwaRegistry: "
+ e.getMessage());
}

List<PwaIcon> icons = registry.getIcons();
// This icon has width 32 and it's generated based on a custom icon (see
// above)
PwaIcon pwaIcon = icons.stream().filter(icon -> icon.getWidth() == 32)
.findFirst().get();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
pwaIcon.write(stream);
// the default image has 47 on the position 36
Assert.assertEquals(26, stream.toByteArray()[36]);
}

private PwaRegistry createPwaRegistryInstance(PWA pwa,
ServletContext servletContext)
throws IllegalAccessException, InvocationTargetException,
InstantiationException, NoSuchMethodException {
Constructor<PwaRegistry> constructor = PwaRegistry.class
.getDeclaredConstructor(PWA.class, ServletContext.class);
constructor.setAccessible(true);
return constructor.newInstance(pwa, servletContext);
}

}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 9d31fe6

Please sign in to comment.