Skip to content

Commit

Permalink
[GEOS-9109] Styles referring to relative icons in subdirectories fail…
Browse files Browse the repository at this point in the history
… to change workspace
  • Loading branch information
aaime committed Jan 29, 2019
1 parent f065f2a commit 99c3336
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 27 deletions.
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,7 +16,23 @@
import java.util.logging.Level; import java.util.logging.Level;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.geoserver.catalog.*; import org.apache.commons.lang3.SystemUtils;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.CoverageStoreInfo;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.catalog.StoreInfo;
import org.geoserver.catalog.StyleInfo;
import org.geoserver.catalog.Styles;
import org.geoserver.catalog.WMSLayerInfo;
import org.geoserver.catalog.WMSStoreInfo;
import org.geoserver.catalog.WMTSLayerInfo;
import org.geoserver.catalog.WMTSStoreInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.platform.GeoServerExtensions; import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader; import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.platform.resource.Paths; import org.geoserver.platform.resource.Paths;
Expand All @@ -26,8 +42,18 @@
import org.geoserver.platform.resource.Resources; import org.geoserver.platform.resource.Resources;
import org.geoserver.util.EntityResolverProvider; import org.geoserver.util.EntityResolverProvider;
import org.geotools.data.DataUtilities; import org.geotools.data.DataUtilities;
import org.geotools.styling.*; import org.geotools.styling.AbstractStyleVisitor;
import org.geotools.styling.ChannelSelection;
import org.geotools.styling.DefaultResourceLocator;
import org.geotools.styling.ExternalGraphic;
import org.geotools.styling.Mark;
import org.geotools.styling.ResourceLocator;
import org.geotools.styling.SelectedChannelType;
import org.geotools.styling.Style;
import org.geotools.styling.StyledLayerDescriptor;
import org.geotools.util.URLs; import org.geotools.util.URLs;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
import org.xml.sax.EntityResolver; import org.xml.sax.EntityResolver;


/** /**
Expand Down Expand Up @@ -1251,7 +1277,7 @@ public File findOrCreateStyleSldFile(StyleInfo s) throws IOException {
if (styleResource.getType() == Type.UNDEFINED) { if (styleResource.getType() == Type.UNDEFINED) {
throw new FileNotFoundException("No such resource: " + s.getFilename()); throw new FileNotFoundException("No such resource: " + s.getFilename());
} }
final DefaultResourceLocator locator = new DefaultResourceLocator(); final DefaultResourceLocator locator = new ResourceAwareResourceLocator();
locator.setSourceUrl(Resources.toURL(styleResource)); locator.setSourceUrl(Resources.toURL(styleResource));
StyledLayerDescriptor sld = StyledLayerDescriptor sld =
Styles.handler(s.getFormat()) Styles.handler(s.getFormat())
Expand Down Expand Up @@ -1392,19 +1418,42 @@ public void visit(ExternalGraphic exgr) {
return; return;
} }
try { try {
Resource r = resourceLoader.fromURL(exgr.getLocation()); final String location = exgr.getURI();
Resource r = resourceLoader.fromURL(location);


if (r != null && r.getType() != Type.UNDEFINED) { if (r != null && r.getType() != Type.UNDEFINED) {
resources.add(r); resources.add(r);
} }
} catch (IllegalArgumentException | MalformedURLException e) { } catch (IllegalArgumentException e) {
GeoServerConfigPersister.LOGGER.log( GeoServerConfigPersister.LOGGER.log(
Level.WARNING, Level.WARNING,
"Error attemping to process SLD resource", "Error attemping to process SLD resource",
e); e);
} }
} }


@Override
public void visit(Mark mark) {
final Expression wellKnownName = mark.getWellKnownName();
if (wellKnownName instanceof Literal) {
final String name = wellKnownName.evaluate(null, String.class);
if (name.startsWith("resource:/")) {
try {
Resource r = resourceLoader.fromURL(name);

if (r != null && r.getType() != Type.UNDEFINED) {
resources.add(r);
}
} catch (IllegalArgumentException e) {
GeoServerConfigPersister.LOGGER.log(
Level.WARNING,
"Error attemping to process SLD resource",
e);
}
}
}
}

// TODO: Workaround for GEOT-4803, Remove when it is fixed, KS // TODO: Workaround for GEOT-4803, Remove when it is fixed, KS
@Override @Override
public void visit(ChannelSelection cs) { public void visit(ChannelSelection cs) {
Expand Down Expand Up @@ -1453,7 +1502,31 @@ public ResourceLocator getResourceLocator() {
return locator; return locator;
} }


private class GeoServerResourceLocator extends DefaultResourceLocator { private class ResourceAwareResourceLocator extends DefaultResourceLocator {
@Override
protected URL validateRelativeURL(URL relativeUrl) {
if (relativeUrl.getProtocol().equalsIgnoreCase("resource")) {
String path = relativeUrl.getPath();
if (resourceLoader.get(path).getType() != Type.UNDEFINED) {
return relativeUrl;
} else {
return null;
}
} else {
return super.validateRelativeURL(relativeUrl);
}
}

@Override
protected URL makeRelativeURL(String uri, String query) {
if (SystemUtils.IS_OS_WINDOWS && uri.contains("\\")) {
uri = uri.replace('\\', '/');
}
return super.makeRelativeURL(uri, query);
}
}

private class GeoServerResourceLocator extends ResourceAwareResourceLocator {


@Override @Override
public URL locateResource(String uri) { public URL locateResource(String uri) {
Expand Down Expand Up @@ -1500,15 +1573,5 @@ public URL locateResource(String uri) {
return url; return url;
} }
} }

@Override
protected URL validateRelativeURL(URL relativeUrl) {
// the resource:/ thing does not make for a valid url, so don't validate it
if (relativeUrl.getProtocol().equalsIgnoreCase("resource")) {
return relativeUrl;
} else {
return super.validateRelativeURL(relativeUrl);
}
}
} }
} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.logging.Logger; import java.util.logging.Logger;
Expand Down Expand Up @@ -75,14 +77,20 @@ public void handleModifyEvent(CatalogModifyEvent event) {
if (source instanceof StyleInfo) { if (source instanceof StyleInfo) {
i = event.getPropertyNames().indexOf("workspace"); i = event.getPropertyNames().indexOf("workspace");
if (i > -1) { if (i > -1) {
WorkspaceInfo oldWorkspace = (WorkspaceInfo) event.getOldValues().get(i);
WorkspaceInfo newWorkspace = (WorkspaceInfo) event.getNewValues().get(i); WorkspaceInfo newWorkspace = (WorkspaceInfo) event.getNewValues().get(i);
Resource oldDir = dd.getStyles(oldWorkspace);
Resource newDir = dd.getStyles(newWorkspace); Resource newDir = dd.getStyles(newWorkspace);
URI oldDirURI = new URI(oldDir.path());


// look for any resource files (image, etc...) and copy them over, don't move // look for any resource files (image, etc...) and copy them over, don't move
// since they could be shared among other styles // since they could be shared among other styles
for (Resource old : dd.additionalStyleResources((StyleInfo) source)) { for (Resource old : dd.additionalStyleResources((StyleInfo) source)) {
if (old.getType() != Type.UNDEFINED) { if (old.getType() != Type.UNDEFINED) {
copyResToDir(old, newDir); URI oldURI = new URI(old.path());
final URI relative = oldDirURI.relativize(oldURI);
final Resource target = newDir.get(relative.getPath()).parent();
copyResToDir(old, target);
} }
} }


Expand All @@ -94,7 +102,7 @@ public void handleModifyEvent(CatalogModifyEvent event) {
} }
} }
} }
} catch (IOException e) { } catch (IOException | URISyntaxException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.io.FileUtils;
import org.geoserver.catalog.CascadeRemovalReporter.ModificationType; import org.geoserver.catalog.CascadeRemovalReporter.ModificationType;
import org.geoserver.catalog.event.CatalogEvent; import org.geoserver.catalog.event.CatalogEvent;
import org.geoserver.catalog.event.CatalogListener; import org.geoserver.catalog.event.CatalogListener;
Expand All @@ -40,6 +41,7 @@
import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.styling.LineSymbolizer; import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.PointSymbolizer; import org.geotools.styling.PointSymbolizer;
import org.geotools.util.Version;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
Expand Down Expand Up @@ -72,21 +74,40 @@ protected void setUpTestData(SystemTestData testData) throws Exception {


@Override @Override
protected void onSetUp(SystemTestData testData) throws IOException { protected void onSetUp(SystemTestData testData) throws IOException {
final Catalog catalog = getCatalog();
testData.addStyle( testData.addStyle(
"singleStyleGroup", "singleStyleGroup", "singleStyleGroup.sld", CatalogIntegrationTest.class, catalog);
"singleStyleGroup.sld",
CatalogIntegrationTest.class,
getCatalog());
testData.addStyle( testData.addStyle(
"multiStyleGroup", "multiStyleGroup", "multiStyleGroup.sld", CatalogIntegrationTest.class, catalog);
"multiStyleGroup.sld",
CatalogIntegrationTest.class,
getCatalog());
testData.addStyle( testData.addStyle(
"recursiveStyleGroup", "recursiveStyleGroup",
"recursiveStyleGroup.sld", "recursiveStyleGroup.sld",
CatalogIntegrationTest.class, CatalogIntegrationTest.class,
getCatalog()); catalog);

// add a style with relative resource references, and resources in sub-directories
testData.addStyle("relative", "se_relativepath.sld", ResourcePoolTest.class, catalog);
StyleInfo style = catalog.getStyleByName("relative");
style.setFormatVersion(new Version("1.1.0"));
catalog.save(style);
File images = new File(testData.getDataDirectoryRoot(), "styles/images");
assertTrue(images.mkdir());
File image = new File("./src/test/resources/org/geoserver/catalog/rockFillSymbol.png");
assertTrue(image.exists());
FileUtils.copyFileToDirectory(image, images);
File svg = new File("./src/test/resources/org/geoserver/catalog/square16.svg");
assertTrue(svg.exists());
FileUtils.copyFileToDirectory(svg, images);

// add a workspace for style move testing
final CatalogFactory factory = catalog.getFactory();
final WorkspaceInfo secondaryWs = factory.createWorkspace();
secondaryWs.setName("secondary");
final NamespaceInfo secondaryNs = factory.createNamespace();
secondaryNs.setPrefix("secondary");
secondaryNs.setURI("http://www.geoserver.org/secondary");
catalog.add(secondaryWs);
catalog.add(secondaryNs);
} }


@Test @Test
Expand Down Expand Up @@ -598,4 +619,22 @@ public void testReloadDefaultStyles() throws Exception {
final StyleInfo point = getCatalog().getStyleByName("point"); final StyleInfo point = getCatalog().getStyleByName("point");
assertNotNull(point); assertNotNull(point);
} }

@Test
public void testChangeStyleWorkspaceRelativeResources() throws Exception {
// move style to a different workspace
final Catalog catalog = getCatalog();
final StyleInfo style = catalog.getStyleByName("relative");
final WorkspaceInfo secondaryWs = catalog.getWorkspaceByName("secondary");
style.setWorkspace(secondaryWs);
catalog.save(style);

// check the referenced image and svg has been moved keeping the relative position
final Resource relativeImage =
getDataDirectory().getStyles(secondaryWs, "images", "rockFillSymbol.png");
assertEquals(Resource.Type.RESOURCE, relativeImage.getType());
final Resource relativeSvg =
getDataDirectory().getStyles(secondaryWs, "images", "square16.svg");
assertEquals(Resource.Type.RESOURCE, relativeSvg.getType());
}
} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@
</se:GraphicFill> </se:GraphicFill>
</se:Fill> </se:Fill>
</se:PolygonSymbolizer> </se:PolygonSymbolizer>
<se:PolygonSymbolizer>
<se:Fill>
<se:GraphicFill>
<se:Graphic>
<se:Mark>
<se:WellKnownName>file://images/square16.svg</se:WellKnownName>
<se:Fill>
<se:SvgParameter name="fill">0xFF0000</se:SvgParameter>
</se:Fill>
</se:Mark>
</se:Graphic>
</se:GraphicFill>
</se:Fill>
</se:PolygonSymbolizer>
</se:Rule> </se:Rule>
</se:FeatureTypeStyle> </se:FeatureTypeStyle>
</UserStyle> </UserStyle>
Expand Down
64 changes: 64 additions & 0 deletions src/main/src/test/resources/org/geoserver/catalog/square16.svg
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 99c3336

Please sign in to comment.