{"action":"created","comment":{"url":"https://api.github.com/repos/geotools/geotools/pulls/comments/193105044","pull_request_review_id":126010600,"id":193105044,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5MzEwNTA0NA==","diff_hunk":"@@ -0,0 +1,260 @@\n+/*\n+ *    GeoTools - The Open Source Java GIS Toolkit\n+ *    http://geotools.org\n+ *\n+ *    (C) 2017, Open Source Geospatial Foundation (OSGeo)\n+ *\n+ *    This library is free software; you can redistribute it and/or\n+ *    modify it under the terms of the GNU Lesser General Public\n+ *    License as published by the Free Software Foundation;\n+ *    version 2.1 of the License.\n+ *\n+ *    This library is distributed in the hope that it will be useful,\n+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+ *    Lesser General Public License for more details.\n+ */\n+package org.geotools.renderer.style;\n+\n+import java.awt.RenderingHints.Key;\n+import java.io.IOException;\n+import java.io.UnsupportedEncodingException;\n+import java.net.URL;\n+import java.net.URLDecoder;\n+import java.util.AbstractMap.SimpleImmutableEntry;\n+import java.util.Arrays;\n+import java.util.Collections;\n+import java.util.HashSet;\n+import java.util.Map;\n+import java.util.Set;\n+import java.util.regex.Matcher;\n+import java.util.regex.Pattern;\n+import java.util.stream.Collectors;\n+import org.apache.batik.dom.svg.SAXSVGDocumentFactory;\n+import org.apache.batik.util.XMLResourceDescriptor;\n+import org.geotools.factory.GeoTools;\n+import org.geotools.factory.Hints;\n+import org.geotools.util.Converters;\n+import org.geotools.util.SoftValueHashMap;\n+import org.geotools.xml.NullEntityResolver;\n+import org.opengis.feature.Feature;\n+import org.opengis.filter.expression.Expression;\n+import org.w3c.dom.Document;\n+import org.w3c.dom.Element;\n+import org.w3c.dom.NamedNodeMap;\n+import org.w3c.dom.Node;\n+import org.w3c.dom.NodeList;\n+import org.xml.sax.EntityResolver;\n+import org.xml.sax.InputSource;\n+import org.xml.sax.SAXException;\n+\n+/** Cache for RenderableSVG instances */\n+public class RenderableSVGCache {\n+\n+    private static final Pattern PARAMETER_PATTERN = Pattern.compile(\"param\\\\((.+)\\\\).*\");\n+\n+    /** Parsed SVG glyphs cache */\n+    static Map<String, RenderableSVG> glyphCache =\n+            Collections.synchronizedMap(new SoftValueHashMap<>());\n+\n+    /** The possible mime types for SVG */\n+    static final Set<String> formats = new HashSet<String>();\n+\n+    static {\n+        formats.add(\"image/svg\");\n+        formats.add(\"image/svg-xml\");\n+        formats.add(\"image/svg+xml\");\n+    }\n+\n+    private EntityResolver resolver;\n+\n+    public RenderableSVGCache() {\n+        this(null);\n+    }\n+\n+    public RenderableSVGCache(Map<Key, Object> hints) {\n+        if (hints != null && hints.containsKey(Hints.ENTITY_RESOLVER)) {\n+            // use entity resolver provided (even if null)\n+            this.resolver = (EntityResolver) hints.get(Hints.ENTITY_RESOLVER);\n+\n+            if (this.resolver == null) { // use null instance rather than check each time\n+                this.resolver = NullEntityResolver.INSTANCE;\n+            }\n+        } else {\n+            this.resolver = GeoTools.getEntityResolver(null);\n+        }\n+    }\n+\n+    public RenderableSVG getRenderableSVG(Feature feature, Expression url, String format)\n+            throws Exception {\n+        // check we do support the declared format\n+        if (format == null || !formats.contains(format.toLowerCase())) return null;\n+\n+        // grab the url\n+        String svgfile = url.evaluate(feature, String.class);\n+        if (svgfile == null) {\n+            throw new IllegalArgumentException(\n+                    \"The specified expression could not be turned into an URL\");\n+        } else {\n+            // just for validation parse the URL\n+            if (Converters.convert(svgfile, URL.class) == null) {\n+                throw new IllegalArgumentException(\"Invalid URL: \" + svgfile);\n+            }\n+        }\n+\n+        // turn the svg into a document and cache results\n+        RenderableSVG svg = glyphCache.get(svgfile);\n+        if (svg == null) {\n+            String parser = XMLResourceDescriptor.getXMLParserClassName();\n+            SAXSVGDocumentFactory f =\n+                    new SAXSVGDocumentFactory(parser) {\n+                        @Override\n+                        public InputSource resolveEntity(String publicId, String systemId)\n+                                throws SAXException {\n+                            InputSource source = super.resolveEntity(publicId, systemId);\n+                            if (source == null) {","path":"modules/plugin/svg/src/main/java/org/geotools/renderer/style/RenderableSVGCache.java","position":115,"original_position":115,"commit_id":"dd402dbaa7ac68fb7fed87286f884f08c69c98ab","original_commit_id":"58c83d788ec14f69d07e03bbc5a82acea0f7ef7d","user":{"login":"nmco","id":1590542,"node_id":"MDQ6VXNlcjE1OTA1NDI=","avatar_url":"https://avatars1.githubusercontent.com/u/1590542?v=4","gravatar_id":"","url":"https://api.github.com/users/nmco","html_url":"https://github.com/nmco","followers_url":"https://api.github.com/users/nmco/followers","following_url":"https://api.github.com/users/nmco/following{/other_user}","gists_url":"https://api.github.com/users/nmco/gists{/gist_id}","starred_url":"https://api.github.com/users/nmco/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nmco/subscriptions","organizations_url":"https://api.github.com/users/nmco/orgs","repos_url":"https://api.github.com/users/nmco/repos","events_url":"https://api.github.com/users/nmco/events{/privacy}","received_events_url":"https://api.github.com/users/nmco/received_events","type":"User","site_admin":false},"body":"Ah! thanks for the info.","created_at":"2018-06-05T14:56:56Z","updated_at":"2018-06-05T14:56:56Z","html_url":"https://github.com/geotools/geotools/pull/1902#discussion_r193105044","pull_request_url":"https://api.github.com/repos/geotools/geotools/pulls/1902","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/geotools/geotools/pulls/comments/193105044"},"html":{"href":"https://github.com/geotools/geotools/pull/1902#discussion_r193105044"},"pull_request":{"href":"https://api.github.com/repos/geotools/geotools/pulls/1902"}},"in_reply_to_id":192678956},"pull_request":{"url":"https://api.github.com/repos/geotools/geotools/pulls/1902","id":189706641,"node_id":"MDExOlB1bGxSZXF1ZXN0MTg5NzA2NjQx","html_url":"https://github.com/geotools/geotools/pull/1902","diff_url":"https://github.com/geotools/geotools/pull/1902.diff","patch_url":"https://github.com/geotools/geotools/pull/1902.patch","issue_url":"https://api.github.com/repos/geotools/geotools/issues/1902","number":1902,"state":"open","locked":false,"title":"[GEOT-6024] Allow usage of SVGs as mark sources (fillable/strokable shapes, instead of finished symbols)","user":{"login":"aaime","id":325433,"node_id":"MDQ6VXNlcjMyNTQzMw==","avatar_url":"https://avatars3.githubusercontent.com/u/325433?v=4","gravatar_id":"","url":"https://api.github.com/users/aaime","html_url":"https://github.com/aaime","followers_url":"https://api.github.com/users/aaime/followers","following_url":"https://api.github.com/users/aaime/following{/other_user}","gists_url":"https://api.github.com/users/aaime/gists{/gist_id}","starred_url":"https://api.github.com/users/aaime/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aaime/subscriptions","organizations_url":"https://api.github.com/users/aaime/orgs","repos_url":"https://api.github.com/users/aaime/repos","events_url":"https://api.github.com/users/aaime/events{/privacy}","received_events_url":"https://api.github.com/users/aaime/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-05-22T15:37:24Z","updated_at":"2018-06-05T14:56:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1a9823eb893e3a93f1a83dfc5a642bd2f8a17c0e","assignee":null,"assignees":[],"requested_reviewers":[{"login":"ianturton","id":122529,"node_id":"MDQ6VXNlcjEyMjUyOQ==","avatar_url":"https://avatars3.githubusercontent.com/u/122529?v=4","gravatar_id":"","url":"https://api.github.com/users/ianturton","html_url":"https://github.com/ianturton","followers_url":"https://api.github.com/users/ianturton/followers","following_url":"https://api.github.com/users/ianturton/following{/other_user}","gists_url":"https://api.github.com/users/ianturton/gists{/gist_id}","starred_url":"https://api.github.com/users/ianturton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ianturton/subscriptions","organizations_url":"https://api.github.com/users/ianturton/orgs","repos_url":"https://api.github.com/users/ianturton/repos","events_url":"https://api.github.com/users/ianturton/events{/privacy}","received_events_url":"https://api.github.com/users/ianturton/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/geotools/geotools/pulls/1902/commits","review_comments_url":"https://api.github.com/repos/geotools/geotools/pulls/1902/comments","review_comment_url":"https://api.github.com/repos/geotools/geotools/pulls/comments{/number}","comments_url":"https://api.github.com/repos/geotools/geotools/issues/1902/comments","statuses_url":"https://api.github.com/repos/geotools/geotools/statuses/dd402dbaa7ac68fb7fed87286f884f08c69c98ab","head":{"label":"aaime:svg_mark","ref":"svg_mark","sha":"dd402dbaa7ac68fb7fed87286f884f08c69c98ab","user":{"login":"aaime","id":325433,"node_id":"MDQ6VXNlcjMyNTQzMw==","avatar_url":"https://avatars3.githubusercontent.com/u/325433?v=4","gravatar_id":"","url":"https://api.github.com/users/aaime","html_url":"https://github.com/aaime","followers_url":"https://api.github.com/users/aaime/followers","following_url":"https://api.github.com/users/aaime/following{/other_user}","gists_url":"https://api.github.com/users/aaime/gists{/gist_id}","starred_url":"https://api.github.com/users/aaime/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aaime/subscriptions","organizations_url":"https://api.github.com/users/aaime/orgs","repos_url":"https://api.github.com/users/aaime/repos","events_url":"https://api.github.com/users/aaime/events{/privacy}","received_events_url":"https://api.github.com/users/aaime/received_events","type":"User","site_admin":false},"repo":{"id":4835074,"node_id":"MDEwOlJlcG9zaXRvcnk0ODM1MDc0","name":"geotools","full_name":"aaime/geotools","owner":{"login":"aaime","id":325433,"node_id":"MDQ6VXNlcjMyNTQzMw==","avatar_url":"https://avatars3.githubusercontent.com/u/325433?v=4","gravatar_id":"","url":"https://api.github.com/users/aaime","html_url":"https://github.com/aaime","followers_url":"https://api.github.com/users/aaime/followers","following_url":"https://api.github.com/users/aaime/following{/other_user}","gists_url":"https://api.github.com/users/aaime/gists{/gist_id}","starred_url":"https://api.github.com/users/aaime/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aaime/subscriptions","organizations_url":"https://api.github.com/users/aaime/orgs","repos_url":"https://api.github.com/users/aaime/repos","events_url":"https://api.github.com/users/aaime/events{/privacy}","received_events_url":"https://api.github.com/users/aaime/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/aaime/geotools","description":"Mirror of central GeoTools svn repository","fork":true,"url":"https://api.github.com/repos/aaime/geotools","forks_url":"https://api.github.com/repos/aaime/geotools/forks","keys_url":"https://api.github.com/repos/aaime/geotools/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aaime/geotools/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aaime/geotools/teams","hooks_url":"https://api.github.com/repos/aaime/geotools/hooks","issue_events_url":"https://api.github.com/repos/aaime/geotools/issues/events{/number}","events_url":"https://api.github.com/repos/aaime/geotools/events","assignees_url":"https://api.github.com/repos/aaime/geotools/assignees{/user}","branches_url":"https://api.github.com/repos/aaime/geotools/branches{/branch}","tags_url":"https://api.github.com/repos/aaime/geotools/tags","blobs_url":"https://api.github.com/repos/aaime/geotools/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aaime/geotools/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aaime/geotools/git/refs{/sha}","trees_url":"https://api.github.com/repos/aaime/geotools/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aaime/geotools/statuses/{sha}","languages_url":"https://api.github.com/repos/aaime/geotools/languages","stargazers_url":"https://api.github.com/repos/aaime/geotools/stargazers","contributors_url":"https://api.github.com/repos/aaime/geotools/contributors","subscribers_url":"https://api.github.com/repos/aaime/geotools/subscribers","subscription_url":"https://api.github.com/repos/aaime/geotools/subscription","commits_url":"https://api.github.com/repos/aaime/geotools/commits{/sha}","git_commits_url":"https://api.github.com/repos/aaime/geotools/git/commits{/sha}","comments_url":"https://api.github.com/repos/aaime/geotools/comments{/number}","issue_comment_url":"https://api.github.com/repos/aaime/geotools/issues/comments{/number}","contents_url":"https://api.github.com/repos/aaime/geotools/contents/{+path}","compare_url":"https://api.github.com/repos/aaime/geotools/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aaime/geotools/merges","archive_url":"https://api.github.com/repos/aaime/geotools/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aaime/geotools/downloads","issues_url":"https://api.github.com/repos/aaime/geotools/issues{/number}","pulls_url":"https://api.github.com/repos/aaime/geotools/pulls{/number}","milestones_url":"https://api.github.com/repos/aaime/geotools/milestones{/number}","notifications_url":"https://api.github.com/repos/aaime/geotools/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aaime/geotools/labels{/name}","releases_url":"https://api.github.com/repos/aaime/geotools/releases{/id}","deployments_url":"https://api.github.com/repos/aaime/geotools/deployments","created_at":"2012-06-29T17:32:49Z","updated_at":"2014-10-06T10:37:52Z","pushed_at":"2018-06-05T14:32:52Z","git_url":"git://github.com/aaime/geotools.git","ssh_url":"git@github.com:aaime/geotools.git","clone_url":"https://github.com/aaime/geotools.git","svn_url":"https://github.com/aaime/geotools","homepage":"http://geotools.org","size":182616,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":1,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"geotools:master","ref":"master","sha":"d6b6b00c2227b0379c940043eba01180aca86eb3","user":{"login":"geotools","id":1187031,"node_id":"MDEyOk9yZ2FuaXphdGlvbjExODcwMzE=","avatar_url":"https://avatars2.githubusercontent.com/u/1187031?v=4","gravatar_id":"","url":"https://api.github.com/users/geotools","html_url":"https://github.com/geotools","followers_url":"https://api.github.com/users/geotools/followers","following_url":"https://api.github.com/users/geotools/following{/other_user}","gists_url":"https://api.github.com/users/geotools/gists{/gist_id}","starred_url":"https://api.github.com/users/geotools/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/geotools/subscriptions","organizations_url":"https://api.github.com/users/geotools/orgs","repos_url":"https://api.github.com/users/geotools/repos","events_url":"https://api.github.com/users/geotools/events{/privacy}","received_events_url":"https://api.github.com/users/geotools/received_events","type":"Organization","site_admin":false},"repo":{"id":2752522,"node_id":"MDEwOlJlcG9zaXRvcnkyNzUyNTIy","name":"geotools","full_name":"geotools/geotools","owner":{"login":"geotools","id":1187031,"node_id":"MDEyOk9yZ2FuaXphdGlvbjExODcwMzE=","avatar_url":"https://avatars2.githubusercontent.com/u/1187031?v=4","gravatar_id":"","url":"https://api.github.com/users/geotools","html_url":"https://github.com/geotools","followers_url":"https://api.github.com/users/geotools/followers","following_url":"https://api.github.com/users/geotools/following{/other_user}","gists_url":"https://api.github.com/users/geotools/gists{/gist_id}","starred_url":"https://api.github.com/users/geotools/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/geotools/subscriptions","organizations_url":"https://api.github.com/users/geotools/orgs","repos_url":"https://api.github.com/users/geotools/repos","events_url":"https://api.github.com/users/geotools/events{/privacy}","received_events_url":"https://api.github.com/users/geotools/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/geotools/geotools","description":"Official GeoTools repository","fork":false,"url":"https://api.github.com/repos/geotools/geotools","forks_url":"https://api.github.com/repos/geotools/geotools/forks","keys_url":"https://api.github.com/repos/geotools/geotools/keys{/key_id}","collaborators_url":"https://api.github.com/repos/geotools/geotools/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/geotools/geotools/teams","hooks_url":"https://api.github.com/repos/geotools/geotools/hooks","issue_events_url":"https://api.github.com/repos/geotools/geotools/issues/events{/number}","events_url":"https://api.github.com/repos/geotools/geotools/events","assignees_url":"https://api.github.com/repos/geotools/geotools/assignees{/user}","branches_url":"https://api.github.com/repos/geotools/geotools/branches{/branch}","tags_url":"https://api.github.com/repos/geotools/geotools/tags","blobs_url":"https://api.github.com/repos/geotools/geotools/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/geotools/geotools/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/geotools/geotools/git/refs{/sha}","trees_url":"https://api.github.com/repos/geotools/geotools/git/trees{/sha}","statuses_url":"https://api.github.com/repos/geotools/geotools/statuses/{sha}","languages_url":"https://api.github.com/repos/geotools/geotools/languages","stargazers_url":"https://api.github.com/repos/geotools/geotools/stargazers","contributors_url":"https://api.github.com/repos/geotools/geotools/contributors","subscribers_url":"https://api.github.com/repos/geotools/geotools/subscribers","subscription_url":"https://api.github.com/repos/geotools/geotools/subscription","commits_url":"https://api.github.com/repos/geotools/geotools/commits{/sha}","git_commits_url":"https://api.github.com/repos/geotools/geotools/git/commits{/sha}","comments_url":"https://api.github.com/repos/geotools/geotools/comments{/number}","issue_comment_url":"https://api.github.com/repos/geotools/geotools/issues/comments{/number}","contents_url":"https://api.github.com/repos/geotools/geotools/contents/{+path}","compare_url":"https://api.github.com/repos/geotools/geotools/compare/{base}...{head}","merges_url":"https://api.github.com/repos/geotools/geotools/merges","archive_url":"https://api.github.com/repos/geotools/geotools/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/geotools/geotools/downloads","issues_url":"https://api.github.com/repos/geotools/geotools/issues{/number}","pulls_url":"https://api.github.com/repos/geotools/geotools/pulls{/number}","milestones_url":"https://api.github.com/repos/geotools/geotools/milestones{/number}","notifications_url":"https://api.github.com/repos/geotools/geotools/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/geotools/geotools/labels{/name}","releases_url":"https://api.github.com/repos/geotools/geotools/releases{/id}","deployments_url":"https://api.github.com/repos/geotools/geotools/deployments","created_at":"2011-11-10T23:22:12Z","updated_at":"2018-06-05T14:39:09Z","pushed_at":"2018-06-05T14:39:06Z","git_url":"git://github.com/geotools/geotools.git","ssh_url":"git@github.com:geotools/geotools.git","clone_url":"https://github.com/geotools/geotools.git","svn_url":"https://github.com/geotools/geotools","homepage":"http://geotools.org","size":182134,"stargazers_count":557,"watchers_count":557,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":658,"mirror_url":null,"archived":false,"open_issues_count":8,"license":null,"forks":658,"open_issues":8,"watchers":557,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/geotools/geotools/pulls/1902"},"html":{"href":"https://github.com/geotools/geotools/pull/1902"},"issue":{"href":"https://api.github.com/repos/geotools/geotools/issues/1902"},"comments":{"href":"https://api.github.com/repos/geotools/geotools/issues/1902/comments"},"review_comments":{"href":"https://api.github.com/repos/geotools/geotools/pulls/1902/comments"},"review_comment":{"href":"https://api.github.com/repos/geotools/geotools/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/geotools/geotools/pulls/1902/commits"},"statuses":{"href":"https://api.github.com/repos/geotools/geotools/statuses/dd402dbaa7ac68fb7fed87286f884f08c69c98ab"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"nmco"}}