From 654bfe3cfda53b9d6bf6b33d3d8880f3337a6e6c Mon Sep 17 00:00:00 2001 From: Francesco Mangiacrapa Date: Thu, 16 Jun 2016 16:12:05 +0000 Subject: [PATCH] 4250: Geonetwork Resolver upgrade: it must return only "private" Metadata Ids for CKAN harversting Task-Url: https://support.d4science.org/issues/4250 Ultimated.. another todo remains git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/data-transfer/uri-resolver@129150 82a268e6-3cf1-43bd-a215-b396298e98cf --- GetResponseRecords.xml | 230 --------- .../resolver/GeonetworkRequestDecoder.java | 2 - .../resolver/UriResolverRewriteFilter.java | 32 -- .../gis/geonetwork/FilterGetRecords.java | 12 + .../gis/geonetwork/GeonetworkResolver.java | 9 +- .../gis/geonetwork/ReusableInputStream.java | 78 +++ .../gis/util/GetResponseRecordFilter.java | 79 ++- src/test/resources/GetResponseRecords.xml | 466 ++++++++++++++++++ 8 files changed, 618 insertions(+), 290 deletions(-) delete mode 100644 GetResponseRecords.xml create mode 100644 src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/ReusableInputStream.java create mode 100644 src/test/resources/GetResponseRecords.xml diff --git a/GetResponseRecords.xml b/GetResponseRecords.xml deleted file mode 100644 index 41e625e..0000000 --- a/GetResponseRecords.xml +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - fao-species-map-heg - FAO aquatic species distribution map of Heterodontus galeatus - dataset - FAO - FIGIS - fishery - fisheries - aquatic species distribution - Species distribution - 276695 - Heterodontus galeatus - HEG - Crested bullhead shark - Heterodontus galeatus - Heterodontidae - HETERODONTIFORMES - 12656 - fao-species-map-heg - http://www.fao.org/figis/lod/flod/entities/codedentity/eb7d98c4c597b05ce18ce35345af2eedbbc50ef2 - biota - boundaries - 2015-10-07 - The main sources of information for the species distribution are the habitat description and geographic range contained in the published FAO Catalogues of Species (more details at http://www.fao.org/fishery/fishfinder ). Terms used in the descriptive context of the FAO Catalogues were converted in standard depth, geographic and ecological regions and inserted into a Geographic Information System. - - - fao-species-map-hef - FAO aquatic species distribution map of Heterodontus francisci - dataset - FAO - FIGIS - fishery - fisheries - aquatic species distribution - Species distribution - 276694 - Heterodontus francisci - HEF - Horn shark - Heterodontus francisci - Heterodontidae - HETERODONTIFORMES - 12655 - fao-species-map-hef - http://www.fao.org/figis/lod/flod/entities/codedentity/a2a9b6439ce74eaf2a28afc6bef57eec6ec950b0 - biota - boundaries - 2015-10-07 - The main sources of information for the species distribution are the habitat description and geographic range contained in the published FAO Catalogues of Species (more details at http://www.fao.org/fishery/fishfinder ). Terms used in the descriptive context of the FAO Catalogues were converted in standard depth, geographic and ecological regions and inserted into a Geographic Information System. - - - fao-fsa-map-41.1.3 - Salvador (Division 41.1.3 of FAO Major Area 41) - dataset - FAO - FIGIS - fishery - fisheries - fishery statistical areas - Area management/restriction/regulation zones and reporting units - http://www.fao.org/figis/lod/flod/entities/codedentity/415720c1e1813e22dd87f453e20b1fbd4c560207 - fao-fsa-map-41.1.3 - 41.1.3 - Salvador (Division 41.1.3 of FAO Major Area 41) - DIVISION - boundaries - fao-fsa-map-41.1 - 2015-10-13 - The FAO major fishing areas for statistical purpose are defined by the CWP handbook of fishery statistical standards available at http://www.fao.org/fishery/cwp/handbook/h/en - - - fao-species-map-cre - FAO aquatic species distribution map of Cancer pagurus - dataset - FAO - FIGIS - fishery - fisheries - aquatic species distribution - Species distribution - 2627 - http://www.fao.org/figis/lod/flod/entities/codedentity/c3518fda2e3c6765711757a92d24e57408eea429 - CRE - Edible crab - Cancer pagurus - Cancridae - BRACHYURA - fao-species-map-cre - biota - boundaries - 2015-10-07 - The main sources of information for the species distribution are the habitat description and geographic range contained in the published FAO Catalogues of Species (more details at http://www.fao.org/fishery/fishfinder ). Terms used in the descriptive context of the FAO Catalogues were converted in standard depth, geographic and ecological regions and inserted into a Geographic Information System. - - - fao-fsa-map-41.1.4 - Nothern Oceanic (Division 41.1.4 of FAO Major Area 41) - dataset - FAO - FIGIS - fishery - fisheries - fishery statistical areas - Area management/restriction/regulation zones and reporting units - http://www.fao.org/figis/lod/flod/entities/codedentity/b1d33b4be19ed2dc28e9b53b7087b77ac9821662 - fao-fsa-map-41.1.4 - 41.1.4 - Nothern Oceanic (Division 41.1.4 of FAO Major Area 41) - DIVISION - boundaries - fao-fsa-map-41.1 - 2015-10-13 - The FAO major fishing areas for statistical purpose are defined by the CWP handbook of fishery statistical standards available at http://www.fao.org/fishery/cwp/handbook/h/en - - - fao-species-map-hea - FAO aquatic species distribution map of Heterodontus ramalheira - dataset - FAO - FIGIS - fishery - fisheries - aquatic species distribution - Species distribution - 217626 - Heterodontus ramalheira - HEA - Whitespotted bullhead shark - Heterodontus ramalheira - Heterodontidae - HETERODONTIFORMES - 12661 - fao-species-map-hea - http://www.fao.org/figis/lod/flod/entities/codedentity/be06aeb63705419c7b4c0912078337d03dbe708d - biota - boundaries - 2015-10-07 - The main sources of information for the species distribution are the habitat description and geographic range contained in the published FAO Catalogues of Species (more details at http://www.fao.org/fishery/fishfinder ). Terms used in the descriptive context of the FAO Catalogues were converted in standard depth, geographic and ecological regions and inserted into a Geographic Information System. - - - fao-species-map-crb - FAO aquatic species distribution map of Callinectes sapidus - dataset - FAO - FIGIS - fishery - fisheries - aquatic species distribution - Species distribution - 2632 - http://www.fao.org/figis/lod/flod/entities/codedentity/3fe12b2c0394298dd5338da522bebadadf422326 - CRB - Blue crab - Callinectes sapidus - Portunidae - BRACHYURA - fao-species-map-crb - biota - boundaries - 2015-10-07 - The main sources of information for the species distribution are the habitat description and geographic range contained in the published FAO Catalogues of Species (more details at http://www.fao.org/fishery/fishfinder ). Terms used in the descriptive context of the FAO Catalogues were converted in standard depth, geographic and ecological regions and inserted into a Geographic Information System. - - - fao-species-map-zbl - FAO aquatic species distribution map of Bathothauma lyromma - dataset - FAO - FIGIS - fishery - fisheries - aquatic species distribution - Species distribution - 20437 - http://www.fao.org/figis/lod/flod/entities/codedentity/b9e91f69580e800b8d1f7d7ee232e7f0bdbd4b47 - ZBL - Lyre cranch squid - Bathothauma lyromma - Cranchiidae - CEPHALOPODA - fao-species-map-zbl - biota - boundaries - 2015-10-27 - The main sources of information for the species distribution are the habitat description and geographic range contained in the published FAO Catalogues of Species (more details at http://www.fao.org/fishery/fishfinder ). Terms used in the descriptive context of the FAO Catalogues were converted in standard depth, geographic and ecological regions and inserted into a Geographic Information System. - - - fao-fsa-map-41.1.1 - Amazon (Division 41.1.1 of FAO Major Area 41) - dataset - FAO - FIGIS - fishery - fisheries - fishery statistical areas - Area management/restriction/regulation zones and reporting units - http://www.fao.org/figis/lod/flod/entities/codedentity/323ea512949786623dccbcd8320f24a59686a485 - fao-fsa-map-41.1.1 - 41.1.1 - Amazon (Division 41.1.1 of FAO Major Area 41) - DIVISION - boundaries - fao-fsa-map-41.1 - 2015-10-13 - The FAO major fishing areas for statistical purpose are defined by the CWP handbook of fishery statistical standards available at http://www.fao.org/fishery/cwp/handbook/h/en - - - fao-fsa-map-41.1.2 - Natal (Division 41.1.2 of FAO Major Area 41) - dataset - FAO - FIGIS - fishery - fisheries - fishery statistical areas - Area management/restriction/regulation zones and reporting units - http://www.fao.org/figis/lod/flod/entities/codedentity/ec79700361176dbf80815a9235d71bde3fbc0542 - fao-fsa-map-41.1.2 - 41.1.2 - Natal (Division 41.1.2 of FAO Major Area 41) - DIVISION - boundaries - fao-fsa-map-41.1 - 2015-10-13 - The FAO major fishing areas for statistical purpose are defined by the CWP handbook of fishery statistical standards available at http://www.fao.org/fishery/cwp/handbook/h/en - - - \ No newline at end of file diff --git a/src/main/java/org/gcube/datatransfer/resolver/GeonetworkRequestDecoder.java b/src/main/java/org/gcube/datatransfer/resolver/GeonetworkRequestDecoder.java index 2fccabc..d4cf114 100644 --- a/src/main/java/org/gcube/datatransfer/resolver/GeonetworkRequestDecoder.java +++ b/src/main/java/org/gcube/datatransfer/resolver/GeonetworkRequestDecoder.java @@ -32,8 +32,6 @@ public class GeonetworkRequestDecoder { * @throws ServletException the servlet exception */ public GeonetworkRequestDecoder(String theServletPath, String queryString) throws ServletException{ - - logger.debug("is geonetwork request"); String path = theServletPath; String pathWithoutGN = path.substring(UriResolverRewriteFilter.SERVLET_GEONETWORK.length()+1, path.length()); logger.debug("servlet path without "+UriResolverRewriteFilter.SERVLET_GEONETWORK + " is: " +pathWithoutGN); diff --git a/src/main/java/org/gcube/datatransfer/resolver/UriResolverRewriteFilter.java b/src/main/java/org/gcube/datatransfer/resolver/UriResolverRewriteFilter.java index 48c87ef..75b61c4 100644 --- a/src/main/java/org/gcube/datatransfer/resolver/UriResolverRewriteFilter.java +++ b/src/main/java/org/gcube/datatransfer/resolver/UriResolverRewriteFilter.java @@ -64,38 +64,6 @@ public class UriResolverRewriteFilter implements Filter{ //IS A REQUEST FOR GEONETWORK AUTHENTICATION? (CKAN HARVESTING?) if(isGeonetworkRequest(multiReadRequest.getServletPath())){ - /*String path = multiReadRequest.getServletPath(); - String pathWithoutGN = path.substring(SERVLET_GEONETWORK.length()+1, path.length()); - logger.debug("servlet path without "+SERVLET_GEONETWORK + " is: " +pathWithoutGN); - String[] params = pathWithoutGN.split("/"); - if(params[0]==null || params[0].isEmpty()){ - logger.error("Scope is null or empty, you must set a valid scope /geonetwork/root_vo_vre"); - throw new ServletException("Scope is null or empty, you must set a valid scope /geonetwork/root_vo_vre"); - } - - String scopeValue = getScope(params[0]); - logger.debug("scope value is: "+scopeValue); - String newURI = SERVLET_GEONETWORK + "?" + GeonetworkResolver.SCOPE + "=" + scopeValue; - - if(params.length>1){ - String remainPath = ""; -// newURI +="&remainPath="; - for (int i = 1; i < params.length; i++) { - String httpGetParam = params[i]; - if(httpGetParam!=null && !httpGetParam.isEmpty()) - remainPath+="/"+httpGetParam; - } - newURI +="&"+GeonetworkResolver.REMAIN_PATH+"="+remainPath; - } - - if(queryString!=null && !queryString.isEmpty()) - newURI+="&"+queryString; - - logger.debug("forward "+newURI); - //BODY DEBUG -// String readBody = IOUtils.toString(multiReadRequest.getReader()); -// logger.debug("Read body request: "+readBody); - multiReadRequest.getRequestDispatcher(newURI).forward(multiReadRequest, response);*/ logger.debug("is geonetwork request"); GeonetworkRequestDecoder grd = new GeonetworkRequestDecoder(multiReadRequest.getServletPath(), queryString); logger.debug("forward to: "+grd.getNewURI()); diff --git a/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/FilterGetRecords.java b/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/FilterGetRecords.java index a017f20..dfcf535 100644 --- a/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/FilterGetRecords.java +++ b/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/FilterGetRecords.java @@ -76,4 +76,16 @@ public class FilterGetRecords { } + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + + StringBuilder builder = new StringBuilder(); + builder.append("FilterGetRecords [foundPublicIds="); + builder.append(foundPublicIds); + builder.append("]"); + return builder.toString(); + } } diff --git a/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/GeonetworkResolver.java b/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/GeonetworkResolver.java index e9b95e2..4233905 100644 --- a/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/GeonetworkResolver.java +++ b/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/GeonetworkResolver.java @@ -338,11 +338,14 @@ public class GeonetworkResolver extends HttpServlet{ try{ if(filterGetRecords!=null){ - logger.info("I'm removing list of public IDs, Is it right? "+filterGetRecords); - in = GetResponseRecordFilter.removeSummaryIdsByListIds(new ByteArrayInputStream(byteArray.toByteArray()), filterGetRecords.getFoundPublicIds()); + logger.info("I'm removing list of public IDs with "+filterGetRecords.getFoundPublicIds() +" IDs, Is it right?"); + in = GetResponseRecordFilter.overrideResponseIdsByListIds(in, filterGetRecords.getFoundPublicIds()); } - int bytes = IOUtils.copy(in, out); + ReusableInputStream reus = new ReusableInputStream(in); + int bytes = IOUtils.copy(reus, out); + logger.trace("POST - RETURN : "+IOUtils.toString(reus)); + if(bytes==0) logger.warn("ResponseBody is empty, returning empty resp"); }catch(Exception e){ diff --git a/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/ReusableInputStream.java b/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/ReusableInputStream.java new file mode 100644 index 0000000..60dae80 --- /dev/null +++ b/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/ReusableInputStream.java @@ -0,0 +1,78 @@ +/** + * + */ + +package org.gcube.datatransfer.resolver.gis.geonetwork; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +/** + * @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it Jun 16, 2016 + */ +public class ReusableInputStream extends InputStream { + + private InputStream input; + private ByteArrayOutputStream output; + private ByteBuffer buffer; + + public ReusableInputStream(InputStream input) + throws IOException { + + this.input = input; + this.output = new ByteArrayOutputStream(input.available()); // Note: + // it's + // resizable + // anyway. + } + + @Override + public int read() + throws IOException { + + byte[] b = new byte[1]; + read(b, 0, 1); + return b[0]; + } + + @Override + public int read(byte[] bytes) + throws IOException { + + return read(bytes, 0, bytes.length); + } + + @Override + public int read(byte[] bytes, int offset, int length) + throws IOException { + + if (buffer == null) { + int read = input.read(bytes, offset, length); + if (read <= 0) { + input.close(); + input = null; + buffer = ByteBuffer.wrap(output.toByteArray()); + output = null; + return -1; + } + else { + output.write(bytes, offset, read); + return read; + } + } + else { + int read = Math.min(length, buffer.remaining()); + if (read <= 0) { + buffer.flip(); + return -1; + } + else { + buffer.get(bytes, offset, read); + return read; + } + } + } + // You might want to @Override flush(), close(), etc to delegate to input. +} diff --git a/src/main/java/org/gcube/datatransfer/resolver/gis/util/GetResponseRecordFilter.java b/src/main/java/org/gcube/datatransfer/resolver/gis/util/GetResponseRecordFilter.java index cec6bd7..4a8b615 100644 --- a/src/main/java/org/gcube/datatransfer/resolver/gis/util/GetResponseRecordFilter.java +++ b/src/main/java/org/gcube/datatransfer/resolver/gis/util/GetResponseRecordFilter.java @@ -27,8 +27,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** @@ -38,6 +36,10 @@ import org.w3c.dom.NodeList; */ public class GetResponseRecordFilter { + /** + * + */ + private static final String A_PUBLIC_ID_PLEASE_IGNORE = "A public id please ignore"; public static Logger logger = LoggerFactory.getLogger(GetResponseRecordFilter.class); /** @@ -50,16 +52,17 @@ public class GetResponseRecordFilter { private static boolean deleteSummaryRecord(Document doc, String identifier) { // list - NodeList nodes = doc.getElementsByTagName("csw:SummaryRecord"); - logger.trace("SummaryRecord are: " + nodes.getLength()); + NodeList nodes = doc.getElementsByTagName("gmd:MD_Metadata"); + logger.trace("gmd:MD_Metadata are: " + nodes.getLength()); for (int i = 0; i < nodes.getLength(); i++) { - Element summaryRecord = (Element) nodes.item(i); + Element mdMetadata = (Element) nodes.item(i); // - Element id = (Element) summaryRecord.getElementsByTagName("dc:identifier").item(0); - String idValue = id.getTextContent(); - logger.trace("Summary dc:identifier is: " + idValue); + Element id = (Element) mdMetadata.getElementsByTagName("gmd:fileIdentifier").item(0); + Element gco = (Element) id.getElementsByTagName("gco:CharacterString").item(0); + String idValue = gco.getTextContent(); + logger.trace("Summary gmd:fileIdentifier is: " + idValue); if (idValue.equals(identifier)) { - summaryRecord.getParentNode().removeChild(summaryRecord); + mdMetadata.getParentNode().removeChild(mdMetadata); logger.trace("Removed child " + idValue); return true; } @@ -67,6 +70,34 @@ public class GetResponseRecordFilter { return false; } + /** + * Override summary record. + * + * @param doc the doc + * @param identifier the identifier + * @return true, if successful + */ + private static boolean overrideSummaryRecord(Document doc, String identifier) { + + // list + NodeList nodes = doc.getElementsByTagName("gmd:MD_Metadata"); + logger.debug("gmd:MD_Metadata are: " + nodes.getLength()); + for (int i = 0; i < nodes.getLength(); i++) { + Element mdMetadata = (Element) nodes.item(i); + // + Element id = (Element) mdMetadata.getElementsByTagName("gmd:fileIdentifier").item(0); + Element gco = (Element) id.getElementsByTagName("gco:CharacterString").item(0); + String idValue = gco.getTextContent(); + logger.trace("Summary gmd:fileIdentifier is: " + idValue); + if (idValue.equals(identifier)) { + gco.setTextContent(A_PUBLIC_ID_PLEASE_IGNORE); + logger.debug("Overrided child " + idValue); + return true; + } + } + return false; + } + /** * Removes the summary ids by list ids. @@ -76,7 +107,7 @@ public class GetResponseRecordFilter { * @return the input stream * @throws IOException Signals that an I/O exception has occurred. */ - public static InputStream removeSummaryIdsByListIds(InputStream getRecordsResponse, List idsToRemove) throws IOException { + public static InputStream overrideResponseIdsByListIds(InputStream getRecordsResponse, List idsToRemove) throws IOException { try { // logger.trace("getRecordsResponse is: "+IOUtils.toString(getRecordsResponse)); @@ -85,14 +116,15 @@ public class GetResponseRecordFilter { dbf.setValidating(false); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(bis); - int removed = 0; + int override = 0; for (String identifier : idsToRemove) { - if(deleteSummaryRecord(doc, identifier)) - removed++; + if(overrideSummaryRecord(doc, identifier)) + override++; } - logger.debug("Removed "+removed +" node/s"); + logger.debug("Overrided "+override +" node/s"); - NodeList nodeList = doc.getElementsByTagName("csw:SearchResults"); + //TODO IS IT POSSIBLE TO REMOVE? + /*NodeList nodeList = doc.getElementsByTagName("csw:SearchResults"); if(nodeList!=null && nodeList.item(0)!=null){ Node nd = nodeList.item(0); // update staff attribute @@ -113,8 +145,7 @@ public class GetResponseRecordFilter { }catch (Exception e) { logger.warn("An error occurred during attribe numberOfRecordsMatched updating, skipping operation"); } - } - + }*/ return documentToInputStream(doc); } catch (Exception e) { @@ -143,16 +174,19 @@ public class GetResponseRecordFilter { } + /** + * The main method. + * + * @param args the arguments + */ public static void main(String[] args) { File file = new File("GetResponseRecords.xml"); List idsToRemove = new ArrayList(); - idsToRemove.add("fao-species-map-hef"); - idsToRemove.add("fao-species-map-hea"); - idsToRemove.add("fao-species-map-crb"); - idsToRemove.add("fao-fsa-map-41.1.2"); + idsToRemove.add("fao-species-map-sol"); + idsToRemove.add("fao-species-map-sop"); try { - InputStream is = GetResponseRecordFilter.removeSummaryIdsByListIds(new FileInputStream(file), idsToRemove); + InputStream is = GetResponseRecordFilter.overrideResponseIdsByListIds(new FileInputStream(file), idsToRemove); System.out.println(IOUtils.toString(is)); } @@ -160,6 +194,5 @@ public class GetResponseRecordFilter { // TODO Auto-generated catch block e.printStackTrace(); } - } } diff --git a/src/test/resources/GetResponseRecords.xml b/src/test/resources/GetResponseRecords.xml new file mode 100644 index 0000000..95f9ca1 --- /dev/null +++ b/src/test/resources/GetResponseRecords.xml @@ -0,0 +1,466 @@ + + + + + + + fao-species-map-snk + + + + + + + + + + FAO aquatic species distribution map of Thyrsites atun + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SNK&bbox=-180.0,-90.0,180.0,90.0&width=600&height=300&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + -180.0 + + + -90.0 + + + 180.0 + + + 90.0 + + + + + + + + + + + fao-species-map-soc + + + + + + + + + + FAO aquatic species distribution map of Oncorhynchus nerka + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SOC&bbox=130.0681,32.9042,250.22820000000002,72.0993&width=600&height=196&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + 130.0681 + + + 34.9042 + + + -109.77179999999998 + + + 70.0993 + + + + + + + + + + + fao-species-map-sol + + + + + + + + + + FAO aquatic species distribution map of Solea solea + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SOL&bbox=-19.7671,14.0685,41.4415,68.3647&width=600&height=532&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + -17.7671 + + + 16.0685 + + + 39.4415 + + + 66.3647 + + + + + + + + + + + fao-species-map-son + + + + + + + + + + FAO aquatic species distribution map of Somniosus pacificus + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SON&bbox=117.5364,16.7333,251.3789,75.7452&width=600&height=265&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + 117.5364 + + + 18.7333 + + + -108.62110000000001 + + + 73.7452 + + + + + + + + + + + fao-species-map-sop + + + + + + + + + + FAO aquatic species distribution map of Penaeus notialis + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SOP&bbox=-90.9268,-25.8107,15.8536,25.329&width=600&height=287&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + -88.9268 + + + -23.8107 + + + 13.8536 + + + 23.329 + + + + + + + + + + + fao-species-map-sor + + + + + + + + + + FAO aquatic species distribution map of Somniosus rostratus + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SOR&bbox=-87.429,2.8512000000000004,16.3107,51.051&width=600&height=279&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + -85.429 + + + 4.8512 + + + 14.3107 + + + 49.051 + + + + + + + + + + + fao-species-map-spj + + + + + + + + + + FAO aquatic species distribution map of Sphyrna tiburo + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SPJ&bbox=-122.8181,-34.9314,-23.2731,43.915&width=600&height=475&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + -120.8181 + + + -32.9314 + + + -25.2731 + + + 41.915 + + + + + + + + + + + fao-species-map-spk + + + + + + + + + + FAO aquatic species distribution map of Sphyrna mokarran + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SPK&bbox=-128.5451,-7.0792,152.0144,49.2805&width=600&height=121&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + -126.5451 + + + -5.0792 + + + 150.0144 + + + 47.2805 + + + + + + + + + + + fao-species-map-spl + + + + + + + + + + FAO aquatic species distribution map of Sphyrna lewini + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SPL&bbox=-180.0,-90.0,180.0,90.0&width=600&height=300&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + -180.0 + + + -90.0 + + + 180.0 + + + 90.0 + + + + + + + + + + + fao-species-map-spr + + + + + + + + + + FAO aquatic species distribution map of Sprattus sprattus + + + + + + + http://www.fao.org/figis/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=fifao:UN_CONTINENT2,species:SPECIES_DIST_SPR&bbox=-13.3797,27.8885,43.7761,67.9022&width=600&height=420&srs=EPSG:4326&format=image%2Fpng + + + + + + + + + -11.3797 + + + 29.8885 + + + 41.7761 + + + 65.9022 + + + + + + + + + + \ No newline at end of file