diff --git a/gcube-geonetwork-client/pom.xml b/gcube-geonetwork-client/pom.xml index 60bea48..7fe6b7a 100644 --- a/gcube-geonetwork-client/pom.xml +++ b/gcube-geonetwork-client/pom.xml @@ -20,7 +20,12 @@ - + + + org.gcube.spatial.data + sdi-generic-client + + diff --git a/pom.xml b/pom.xml index 94f0ec8..c86f31c 100644 --- a/pom.xml +++ b/pom.xml @@ -40,10 +40,11 @@ sdi-interface - + sdi-library - + sdi-service + @@ -57,6 +58,39 @@ pom import + + + + + org.gcube.spatial.data + sdi-interface + [1.0.0,2.0.0) + + + + org.gcube.spatial.data + sdi-library + [1.0.0,2.0.0) + + + + org.gcube.spatial.data + sdi-generic-client + [0.0.1-SNAPSHOT,2.0.0) + + + + org.gcube.spatial.data + gcube-geonetwork-client + [0.0.1-SNAPSHOT,2.0.0) + + + + org.gcube.spatial.data + gcube-geoserver-client + [0.0.1-SNAPSHOT,2.0.0) + + diff --git a/sdi-library/.DS_Store b/sdi-library/.DS_Store new file mode 100644 index 0000000..9815476 Binary files /dev/null and b/sdi-library/.DS_Store differ diff --git a/sdi-library/CHANGELOG.md b/sdi-library/CHANGELOG.md new file mode 100644 index 0000000..d1d02ca --- /dev/null +++ b/sdi-library/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog for org.gcube.spatial.data.sdi-library + +## [v1.3.0-SNAPSHOT] 2020-07-21 +- Offer GIS basic functionalities + + +## [v1.2.0] 2020-07-21 + +## Enhancements + +- Application Profile (https://support.d4science.org/issues/18939) + + +### Fixes + +- Integration with gcube distribution (https://support.d4science.org/issues/19612) \ No newline at end of file diff --git a/sdi-library/FUNDING.md b/sdi-library/FUNDING.md new file mode 100644 index 0000000..9e48b94 --- /dev/null +++ b/sdi-library/FUNDING.md @@ -0,0 +1,26 @@ +# Acknowledgments + +The projects leading to this software have received funding from a series of European Union programmes including: + +- the Sixth Framework Programme for Research and Technological Development + - [DILIGENT](https://cordis.europa.eu/project/id/004260) (grant no. 004260). +- the Seventh Framework Programme for research, technological development and demonstration + - [D4Science](https://cordis.europa.eu/project/id/212488) (grant no. 212488); + - [D4Science-II](https://cordis.europa.eu/project/id/239019) (grant no.239019); + - [ENVRI](https://cordis.europa.eu/project/id/283465) (grant no. 283465); + - [iMarine](https://cordis.europa.eu/project/id/283644) (grant no. 283644); + - [EUBrazilOpenBio](https://cordis.europa.eu/project/id/288754) (grant no. 288754). +- the H2020 research and innovation programme + - [SoBigData](https://cordis.europa.eu/project/id/654024) (grant no. 654024); + - [PARTHENOS](https://cordis.europa.eu/project/id/654119) (grant no. 654119); + - [EGI-Engage](https://cordis.europa.eu/project/id/654142) (grant no. 654142); + - [ENVRI PLUS](https://cordis.europa.eu/project/id/654182) (grant no. 654182); + - [BlueBRIDGE](https://cordis.europa.eu/project/id/675680) (grant no. 675680); + - [PerformFISH](https://cordis.europa.eu/project/id/727610) (grant no. 727610); + - [AGINFRA PLUS](https://cordis.europa.eu/project/id/731001) (grant no. 731001); + - [DESIRA](https://cordis.europa.eu/project/id/818194) (grant no. 818194); + - [ARIADNEplus](https://cordis.europa.eu/project/id/823914) (grant no. 823914); + - [RISIS 2](https://cordis.europa.eu/project/id/824091) (grant no. 824091); + - [EOSC-Pillar](https://cordis.europa.eu/project/id/857650) (grant no. 857650); + - [Blue Cloud](https://cordis.europa.eu/project/id/862409) (grant no. 862409); + - [SoBigData-PlusPlus](https://cordis.europa.eu/project/id/871042) (grant no. 871042); diff --git a/sdi-library/LICENSE.md b/sdi-library/LICENSE.md new file mode 100644 index 0000000..3af0507 --- /dev/null +++ b/sdi-library/LICENSE.md @@ -0,0 +1,312 @@ +# European Union Public Licence V. 1.1 + + +EUPL © the European Community 2007 + + +This European Union Public Licence (the “EUPL”) applies to the Work or Software +(as defined below) which is provided under the terms of this Licence. Any use of +the Work, other than as authorised under this Licence is prohibited (to the +extent such use is covered by a right of the copyright holder of the Work). + +The Original Work is provided under the terms of this Licence when the Licensor +(as defined below) has placed the following notice immediately following the +copyright notice for the Original Work: + +Licensed under the EUPL V.1.1 + +or has expressed by any other mean his willingness to license under the EUPL. + + + +## 1. Definitions + +In this Licence, the following terms have the following meaning: + +- The Licence: this Licence. + +- The Original Work or the Software: the software distributed and/or + communicated by the Licensor under this Licence, available as Source Code and + also as Executable Code as the case may be. + +- Derivative Works: the works or software that could be created by the Licensee, + based upon the Original Work or modifications thereof. This Licence does not + define the extent of modification or dependence on the Original Work required + in order to classify a work as a Derivative Work; this extent is determined by + copyright law applicable in the country mentioned in Article 15. + +- The Work: the Original Work and/or its Derivative Works. + +- The Source Code: the human-readable form of the Work which is the most + convenient for people to study and modify. + +- The Executable Code: any code which has generally been compiled and which is + meant to be interpreted by a computer as a program. + +- The Licensor: the natural or legal person that distributes and/or communicates + the Work under the Licence. + +- Contributor(s): any natural or legal person who modifies the Work under the + Licence, or otherwise contributes to the creation of a Derivative Work. + +- The Licensee or “You”: any natural or legal person who makes any usage of the + Software under the terms of the Licence. + +- Distribution and/or Communication: any act of selling, giving, lending, + renting, distributing, communicating, transmitting, or otherwise making + available, on-line or off-line, copies of the Work or providing access to its + essential functionalities at the disposal of any other natural or legal + person. + + + +## 2. Scope of the rights granted by the Licence + +The Licensor hereby grants You a world-wide, royalty-free, non-exclusive, +sub-licensable licence to do the following, for the duration of copyright vested +in the Original Work: + +- use the Work in any circumstance and for all usage, reproduce the Work, modify +- the Original Work, and make Derivative Works based upon the Work, communicate +- to the public, including the right to make available or display the Work or +- copies thereof to the public and perform publicly, as the case may be, the +- Work, distribute the Work or copies thereof, lend and rent the Work or copies +- thereof, sub-license rights in the Work or copies thereof. + +Those rights can be exercised on any media, supports and formats, whether now +known or later invented, as far as the applicable law permits so. + +In the countries where moral rights apply, the Licensor waives his right to +exercise his moral right to the extent allowed by law in order to make effective +the licence of the economic rights here above listed. + +The Licensor grants to the Licensee royalty-free, non exclusive usage rights to +any patents held by the Licensor, to the extent necessary to make use of the +rights granted on the Work under this Licence. + + + +## 3. Communication of the Source Code + +The Licensor may provide the Work either in its Source Code form, or as +Executable Code. If the Work is provided as Executable Code, the Licensor +provides in addition a machine-readable copy of the Source Code of the Work +along with each copy of the Work that the Licensor distributes or indicates, in +a notice following the copyright notice attached to the Work, a repository where +the Source Code is easily and freely accessible for as long as the Licensor +continues to distribute and/or communicate the Work. + + + +## 4. Limitations on copyright + +Nothing in this Licence is intended to deprive the Licensee of the benefits from +any exception or limitation to the exclusive rights of the rights owners in the +Original Work or Software, of the exhaustion of those rights or of other +applicable limitations thereto. + + + +## 5. Obligations of the Licensee + +The grant of the rights mentioned above is subject to some restrictions and +obligations imposed on the Licensee. Those obligations are the following: + +Attribution right: the Licensee shall keep intact all copyright, patent or +trademarks notices and all notices that refer to the Licence and to the +disclaimer of warranties. The Licensee must include a copy of such notices and a +copy of the Licence with every copy of the Work he/she distributes and/or +communicates. The Licensee must cause any Derivative Work to carry prominent +notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes and/or communicates copies of the +Original Works or Derivative Works based upon the Original Work, this +Distribution and/or Communication will be done under the terms of this Licence +or of a later version of this Licence unless the Original Work is expressly +distributed only under this version of the Licence. The Licensee (becoming +Licensor) cannot offer or impose any additional terms or conditions on the Work +or Derivative Work that alter or restrict the terms of the Licence. + +Compatibility clause: If the Licensee Distributes and/or Communicates Derivative +Works or copies thereof based upon both the Original Work and another work +licensed under a Compatible Licence, this Distribution and/or Communication can +be done under the terms of this Compatible Licence. For the sake of this clause, +“Compatible Licence” refers to the licences listed in the appendix attached to +this Licence. Should the Licensee’s obligations under the Compatible Licence +conflict with his/her obligations under this Licence, the obligations of the +Compatible Licence shall prevail. + +Provision of Source Code: When distributing and/or communicating copies of the +Work, the Licensee will provide a machine-readable copy of the Source Code or +indicate a repository where this Source will be easily and freely available for +as long as the Licensee continues to distribute and/or communicate the Work. + +Legal Protection: This Licence does not grant permission to use the trade names, +trademarks, service marks, or names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the copyright notice. + + + +## 6. Chain of Authorship + +The original Licensor warrants that the copyright in the Original Work granted +hereunder is owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each Contributor warrants that the copyright in the modifications he/she brings +to the Work are owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each time You accept the Licence, the original Licensor and subsequent +Contributors grant You a licence to their contributions to the Work, under the +terms of this Licence. + + + +## 7. Disclaimer of Warranty + +The Work is a work in progress, which is continuously improved by numerous +contributors. It is not a finished work and may therefore contain defects or +“bugs” inherent to this type of software development. + +For the above reason, the Work is provided under the Licence on an “as is” basis +and without warranties of any kind concerning the Work, including without +limitation merchantability, fitness for a particular purpose, absence of defects +or errors, accuracy, non-infringement of intellectual property rights other than +copyright as stated in Article 6 of this Licence. + +This disclaimer of warranty is an essential part of the Licence and a condition +for the grant of any rights to the Work. + + + +## 8. Disclaimer of Liability + +Except in the cases of wilful misconduct or damages directly caused to natural +persons, the Licensor will in no event be liable for any direct or indirect, +material or moral, damages of any kind, arising out of the Licence or of the use +of the Work, including without limitation, damages for loss of goodwill, work +stoppage, computer failure or malfunction, loss of data or any commercial +damage, even if the Licensor has been advised of the possibility of such +damage. However, the Licensor will be liable under statutory product liability +laws as far such laws apply to the Work. + + + +## 9. Additional agreements + +While distributing the Original Work or Derivative Works, You may choose to +conclude an additional agreement to offer, and charge a fee for, acceptance of +support, warranty, indemnity, or other liability obligations and/or services +consistent with this Licence. However, in accepting such obligations, You may +act only on your own behalf and on your sole responsibility, not on behalf of +the original Licensor or any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred +by, or claims asserted against such Contributor by the fact You have accepted +any such warranty or additional liability. + + + +## 10. Acceptance of the Licence + +The provisions of this Licence can be accepted by clicking on an icon “I agree” +placed under the bottom of a window displaying the text of this Licence or by +affirming consent in any other similar way, in accordance with the rules of +applicable law. Clicking on that icon indicates your clear and irrevocable +acceptance of this Licence and all of its terms and conditions. + +Similarly, you irrevocably accept this Licence and all of its terms and +conditions by exercising any rights granted to You by Article 2 of this Licence, +such as the use of the Work, the creation by You of a Derivative Work or the +Distribution and/or Communication by You of the Work or copies thereof. + + + +## 11. Information to the public + +In case of any Distribution and/or Communication of the Work by means of +electronic communication by You (for example, by offering to download the Work +from a remote location) the distribution channel or media (for example, a +website) must at least provide to the public the information requested by the +applicable law regarding the Licensor, the Licence and the way it may be +accessible, concluded, stored and reproduced by the Licensee. + + + +## 12. Termination of the Licence + +The Licence and the rights granted hereunder will terminate automatically upon +any breach by the Licensee of the terms of the Licence. + +Such a termination will not terminate the licences of any person who has +received the Work from the Licensee under the Licence, provided such persons +remain in full compliance with the Licence. + + + +## 13. Miscellaneous + +Without prejudice of Article 9 above, the Licence represents the complete +agreement between the Parties as to the Work licensed hereunder. + +If any provision of the Licence is invalid or unenforceable under applicable +law, this will not affect the validity or enforceability of the Licence as a +whole. Such provision will be construed and/or reformed so as necessary to make +it valid and enforceable. + +The European Commission may publish other linguistic versions and/or new +versions of this Licence, so far this is required and reasonable, without +reducing the scope of the rights granted by the Licence. New versions of the +Licence will be published with a unique version number. + +All linguistic versions of this Licence, approved by the European Commission, +have identical value. Parties can take advantage of the linguistic version of +their choice. + + + +## 14. Jurisdiction + +Any litigation resulting from the interpretation of this License, arising +between the European Commission, as a Licensor, and any Licensee, will be +subject to the jurisdiction of the Court of Justice of the European Communities, +as laid down in article 238 of the Treaty establishing the European Community. + +Any litigation arising between Parties, other than the European Commission, and +resulting from the interpretation of this License, will be subject to the +exclusive jurisdiction of the competent court where the Licensor resides or +conducts its primary business. + + + +## 15. Applicable Law + +This Licence shall be governed by the law of the European Union country where +the Licensor resides or has his registered office. + +This licence shall be governed by the Belgian law if: + +- a litigation arises between the European Commission, as a Licensor, and any +- Licensee; the Licensor, other than the European Commission, has no residence +- or registered office inside a European Union country. + + + +## Appendix + + + +“Compatible Licences” according to article 5 EUPL are: + + +- GNU General Public License (GNU GPL) v. 2 + +- Open Software License (OSL) v. 2.1, v. 3.0 + +- Common Public License v. 1.0 + +- Eclipse Public License v. 1.0 + +- Cecill v. 2.0 + diff --git a/sdi-library/README.md b/sdi-library/README.md new file mode 100644 index 0000000..32e592a --- /dev/null +++ b/sdi-library/README.md @@ -0,0 +1,51 @@ +Spatial Data Infrastucture - Library +-------------------------------------------------- + +SDI-Library is one of the subsystems forming the gCube Spatial Data Infrastructure Facilities. It aims to provide gCube Applications simplified feature in order to manage GeoSpatial Data and Metadata. + +## Built with +* [OpenJDK](https://openjdk.java.net/) - The JDK used +* [JAX-RS](https://github.com/eclipse-ee4j/jaxrs-api) - Java™ API for RESTful Web Services +* [Jersey](https://jersey.github.io/) - JAX-RS runtime +* [Maven](https://maven.apache.org/) - Dependency Management + +## Documentation + +Documentation can be found [here](https://gcube.wiki.gcube-system.org/gcube/SDI-Service). + +## Change log + +See [CHANGELOG.md](CHANGELOG.md). + +## License + +This project is licensed under the EUPL V.1.1 License - see the [LICENSE.md](LICENSE.md) file for details. + +## About the gCube Framework +This software is part of the [gCubeFramework](https://www.gcube-system.org/ "gCubeFramework"): an +open-source software toolkit used for building and operating Hybrid Data +Infrastructures enabling the dynamic deployment of Virtual Research Environments +by favouring the realisation of reuse oriented policies. + +The projects leading to this software have received funding from a series of European Union programmes including: + +- the Sixth Framework Programme for Research and Technological Development + - DILIGENT (grant no. 004260). +- the Seventh Framework Programme for research, technological development and demonstration + - D4Science (grant no. 212488); + - D4Science-II (grant no.239019); + - ENVRI (grant no. 283465); + - iMarine(grant no. 283644); + - EUBrazilOpenBio (grant no. 288754). +- the H2020 research and innovation programme + - SoBigData (grant no. 654024); + - PARTHENOS (grant no. 654119); + - EGIEngage (grant no. 654142); + - ENVRIplus (grant no. 654182); + - BlueBRIDGE (grant no. 675680); + - PerformFish (grant no. 727610); + - AGINFRAplus (grant no. 731001); + - DESIRA (grant no. 818194); + - ARIADNEplus (grant no. 823914); + - RISIS2 (grant no. 824091); + diff --git a/sdi-library/pom.xml b/sdi-library/pom.xml new file mode 100644 index 0000000..0b02c58 --- /dev/null +++ b/sdi-library/pom.xml @@ -0,0 +1,99 @@ + + 4.0.0 + + gcube-sdi-suite + org.gcube.spatial.data + 1.0.0-SNAPSHOT + + org.gcube.spatial.data + sdi-library + 1.3.0-SNAPSHOT + SDI Library + Client library to interact with gCube SDI Service + + + scm:git:${gitBaseUrl}/gFeed + scm:git:${gitBaseUrl}/gFeed + ${gitBaseUrl}/gFeed + + + + + org.gcube.core + common-fw-clients + + + + org.gcube.common + authorization-client + + + org.gcube.core + common-generic-clients + + + + org.gcube.core + common-gcube-calls + + + + org.gcube.common + common-jaxrs-client + [1.0.0,2.0.0) + + + + org.gcube.core + common-generic-clients + + + + org.gcube.spatial.data + sdi-interface + + + + + org.glassfish.jersey.core + jersey-client + + + + org.glassfish.jersey.media + jersey-media-json-jackson + + + + org.glassfish.jersey.media + jersey-media-multipart + + + + org.slf4j + slf4j-api + + + + + + junit + junit + 4.10 + test + + + + + + + + ch.qos.logback + logback-classic + test + + + + + + diff --git a/sdi-library/src/main/java/org/gcube/spatial/data/sdi/SDICatalog.java b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/SDICatalog.java new file mode 100644 index 0000000..f4992dd --- /dev/null +++ b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/SDICatalog.java @@ -0,0 +1,14 @@ +package org.gcube.spatial.data.sdi; + +import java.io.File; + +import javax.xml.bind.JAXBException; + + +import org.opengis.metadata.Metadata; + + +public interface SDICatalog { + + +} diff --git a/sdi-library/src/main/java/org/gcube/spatial/data/sdi/SDIClient.java b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/SDIClient.java new file mode 100644 index 0000000..9e94340 --- /dev/null +++ b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/SDIClient.java @@ -0,0 +1,7 @@ +package org.gcube.spatial.data.sdi; + +public interface SDIClient { + + + //public Scope getCurrentConfiguration(); +} diff --git a/sdi-library/src/main/java/org/gcube/spatial/data/sdi/TokenFilter.java b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/TokenFilter.java new file mode 100644 index 0000000..f2a05a8 --- /dev/null +++ b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/TokenFilter.java @@ -0,0 +1,28 @@ +package org.gcube.spatial.data.sdi; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map.Entry; + +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; + +import org.gcube.common.calls.Call; +import org.gcube.common.calls.Interceptors; +import org.gcube.common.calls.Request; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; + + +public class TokenFilter implements ClientRequestFilter { + + @Override + public void filter(final ClientRequestContext rc) throws IOException { + if (ScopeUtils.getCurrentScope()!=null){ + Request requestContext = Interceptors.executeRequestChain(new Call()); + + for (Entry entry: requestContext.getHeaders()){ + rc.getHeaders().put(entry.getKey(), Collections.singletonList((Object)entry.getValue())); + } + } + } +} diff --git a/sdi-library/src/main/java/org/gcube/spatial/data/sdi/plugins/MetadataPlugin.java b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/plugins/MetadataPlugin.java new file mode 100644 index 0000000..b8a40ac --- /dev/null +++ b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/plugins/MetadataPlugin.java @@ -0,0 +1,45 @@ +package org.gcube.spatial.data.sdi.plugins; + +import javax.ws.rs.client.WebTarget; +import javax.xml.namespace.QName; +import javax.xml.transform.dom.DOMResult; +import javax.xml.ws.EndpointReference; + +import org.gcube.common.calls.jaxrs.GcubeService; +import org.gcube.common.calls.jaxrs.TargetFactory; +import org.gcube.common.clients.config.ProxyConfig; +import org.gcube.common.clients.delegates.ProxyDelegate; +import org.gcube.spatial.data.sdi.interfaces.Metadata; +import org.gcube.spatial.data.sdi.model.ServiceConstants; +import org.gcube.spatial.data.sdi.proxies.DefaultMetadata; +import org.w3c.dom.Node; + +public class MetadataPlugin extends SDIAbstractPlugin{ + + public MetadataPlugin() { + super("sdi-service/gcube/service"); + } + + @Override + public Exception convert(Exception arg0, ProxyConfig arg1) { + return arg0; + } + @Override + public Metadata newProxy(ProxyDelegate arg0) { + return new DefaultMetadata(arg0); + } + + @Override + public WebTarget resolve(EndpointReference epr, ProxyConfig arg1) throws Exception { + DOMResult result = new DOMResult(); + epr.writeTo(result); + Node node =result.getNode(); + Node child=node.getFirstChild(); + String address = child.getTextContent(); + GcubeService service = GcubeService.service(). + withName(new QName(ServiceConstants.NAMESPACE,ServiceConstants.Metadata.INTERFACE)). + andPath(ServiceConstants.Metadata.INTERFACE); + return TargetFactory.stubFor(service).at(address); + + } +} diff --git a/sdi-library/src/main/java/org/gcube/spatial/data/sdi/plugins/SDIAbstractPlugin.java b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/plugins/SDIAbstractPlugin.java new file mode 100644 index 0000000..16a3b52 --- /dev/null +++ b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/plugins/SDIAbstractPlugin.java @@ -0,0 +1,62 @@ +package org.gcube.spatial.data.sdi.plugins; + +import javax.ws.rs.client.WebTarget; + +import org.gcube.common.clients.ProxyBuilder; +import org.gcube.common.clients.ProxyBuilderImpl; +import org.gcube.common.clients.Plugin; +import org.gcube.spatial.data.sdi.interfaces.Metadata; +import org.gcube.spatial.data.sdi.model.ServiceConstants; + +public abstract class SDIAbstractPlugin implements Plugin{ + + + private static final MetadataPlugin metadata_plugin=new MetadataPlugin(); + + + public static ProxyBuilder metadata() { + return new ProxyBuilderImpl(metadata_plugin); + } + +// public static ProxyBuilder classification() { +// return new ProxyBuilderImpl(classification_plugin); +// } +// +// public static ProxyBuilder occurrences() { +// return new ProxyBuilderImpl(occurrence_plugin); +// } +// +// public static ProxyBuilder executor() { +// return new ProxyBuilderImpl(executor_plugin); +// } +// +// public static ProxyBuilder resultset(String endpointId) { +// LegacyQuery query = new LegacyQuery(resultset_plugin); +// query.addCondition("$resource/ID/string() eq '"+endpointId+"'"); +// return new ProxyBuilderImpl(resultset_plugin, query); +// } + + + public final String name; + + public SDIAbstractPlugin(String name) { + this.name = name; + } + + @Override + public String serviceClass() { + return ServiceConstants.SERVICE_CLASS; + } + @Override + public String serviceName() { + return ServiceConstants.SERVICE_NAME; + } + @Override + public String name() { + return name; + } + @Override + public String namespace() { + return ServiceConstants.NAMESPACE; + } +} diff --git a/sdi-library/src/main/java/org/gcube/spatial/data/sdi/proxies/DefaultMetadata.java b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/proxies/DefaultMetadata.java new file mode 100644 index 0000000..7360323 --- /dev/null +++ b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/proxies/DefaultMetadata.java @@ -0,0 +1,145 @@ +package org.gcube.spatial.data.sdi.proxies; + +import java.io.File; +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.gcube.common.clients.Call; +import org.gcube.common.clients.delegates.ProxyDelegate; +import org.gcube.spatial.data.sdi.interfaces.Metadata; +import org.gcube.spatial.data.sdi.model.ServiceConstants; +import org.gcube.spatial.data.sdi.model.metadata.MetadataPublishOptions; +import org.gcube.spatial.data.sdi.model.metadata.MetadataReport; +import org.gcube.spatial.data.sdi.model.metadata.TemplateCollection; +import org.gcube.spatial.data.sdi.model.metadata.TemplateDescriptor; +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocation; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; + +public class DefaultMetadata implements Metadata{ + + private final ProxyDelegate delegate; + + + public DefaultMetadata(ProxyDelegate config){ + this.delegate = config; + } + + + + @Override + public TemplateCollection getAvailableTemplates() { + Call> call = new Call>() { + @Override + public Set call(WebTarget templates) throws Exception { + GenericType> generic=new GenericType>() { + }; + return templates.path(ServiceConstants.Metadata.LIST_METHOD).request(MediaType.APPLICATION_JSON).get(generic); + } + }; + try { + return new TemplateCollection(new HashSet(delegate.make(call))); + }catch(Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public MetadataReport pushMetadata(File toPublish) { + return pushMetadata(toPublish, new MetadataPublishOptions()); + } + + @Override + public MetadataReport pushMetadata(final File toPublish, final MetadataPublishOptions options) { + // upload Meta + + Call applyTemplatesCall=null; //needs uploaded id + Call publishCall=null; //needs uploaded id + + try{ + Call uploadCall=new Call() { + + @Override + public String call(WebTarget endpoint) throws Exception { + endpoint.register(MultiPartFeature.class); + FormDataMultiPart multi=new FormDataMultiPart(); +// multi.field("file",toPublish,MediaType.APPLICATION_OCTET_STREAM_TYPE); + FileDataBodyPart fileDataBodyPart = new FileDataBodyPart(ServiceConstants.Metadata.UPLOADED_FILE_PARAMETER, + toPublish,MediaType.APPLICATION_OCTET_STREAM_TYPE); + multi.bodyPart(fileDataBodyPart); + Response resp= endpoint.request().post(Entity.entity(multi, multi.getMediaType())); + checkResponse(resp); + return resp.readEntity(String.class); + } + }; + + + final String id=delegate.make(uploadCall); + + applyTemplatesCall=new Call() { + @Override + public MetadataReport call(WebTarget endpoint) throws Exception { + + + Response resp= endpoint.path(id). + request(MediaType.APPLICATION_JSON).put(Entity.entity( + new HashSet(options.getTemplateInvocations()),MediaType.APPLICATION_JSON)); + checkResponse(resp); + return resp.readEntity(MetadataReport.class); + } + }; + + publishCall=new Call(){ + @Override + public MetadataReport call(WebTarget endpoint) throws Exception { + Response resp= endpoint.path(ServiceConstants.Metadata.PUBLISH_METHOD).path(id).path(options.getGeonetworkCategory()). + queryParam(ServiceConstants.Metadata.VALIDATE_PARAMETER, options.isValidate()). + queryParam(ServiceConstants.Metadata.PUBLIC_PARAMETER, options.isMakePublic()). + queryParam(ServiceConstants.Metadata.STYLESHEET_PARAMETER, options.getGeonetworkStyleSheet()). + request(MediaType.APPLICATION_JSON).get(); + checkResponse(resp); + return resp.readEntity(MetadataReport.class); + } + }; + }catch(Throwable t){ + throw new RuntimeException("Unable to upload file.",t); + } + + + //APPLY TEMPLATES + MetadataReport templateReport =null; + try{ + if(!options.getTemplateInvocations().isEmpty()) + templateReport=delegate.make(applyTemplatesCall); + }catch(Throwable t){ + throw new RuntimeException("Unable to apply templates",t); + } + + //PUBLISH + + + try{ + MetadataReport publishReport=delegate.make(publishCall); + if(templateReport!=null) publishReport.setAppliedTemplates(templateReport.getAppliedTemplates()); + return publishReport; + }catch(Throwable t){ + throw new RuntimeException("Unable to publish metadata. ",t); + } + + } + + + protected void checkResponse(Response toCheck) throws Exception{ + switch(toCheck.getStatusInfo().getFamily()){ + case SUCCESSFUL : break; + default : throw new Exception("Unexpected Response code : "+toCheck.getStatus(),new Exception(toCheck.readEntity(String.class))); + } + } +} diff --git a/sdi-library/src/main/java/org/gcube/spatial/data/sdi/utils/ScopeUtils.java b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/utils/ScopeUtils.java new file mode 100644 index 0000000..860adff --- /dev/null +++ b/sdi-library/src/main/java/org/gcube/spatial/data/sdi/utils/ScopeUtils.java @@ -0,0 +1,40 @@ +package org.gcube.spatial.data.sdi.utils; + +import org.gcube.common.authorization.library.AuthorizationEntry; +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; +import org.gcube.common.scope.api.ScopeProvider; + +import static org.gcube.common.authorization.client.Constants.authorizationService; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ScopeUtils { + + public static String getCurrentScope(){ + try{ + String token=SecurityTokenProvider.instance.get(); + log.debug("Token is : "+token); + if(token==null) throw new Exception("Security Token is null"); + AuthorizationEntry entry = authorizationService().get(token); + return entry.getContext(); + }catch(Exception e ){ + log.debug("Unable to resolve token, checking scope provider..",e); + return ScopeProvider.instance.get(); + } + } + + + public static String getCurrentCaller(){ + try{ + String token=SecurityTokenProvider.instance.get(); + log.debug("Token is : "+token); + if(token==null) throw new Exception("Security Token is null"); + AuthorizationEntry entry = authorizationService().get(token); + return entry.getClientInfo().getId(); + }catch(Exception e ){ + log.debug("Unable to resolve token, checking scope provider..",e); + return "Unidentified data-transfer user"; + } + } +} \ No newline at end of file diff --git a/sdi-library/src/test/java/org/gcube/spatial/data/sdi/MetadataTests.java b/sdi-library/src/test/java/org/gcube/spatial/data/sdi/MetadataTests.java new file mode 100644 index 0000000..ed68f73 --- /dev/null +++ b/sdi-library/src/test/java/org/gcube/spatial/data/sdi/MetadataTests.java @@ -0,0 +1,53 @@ +package org.gcube.spatial.data.sdi; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Paths; + +import org.gcube.spatial.data.sdi.interfaces.Metadata; +import org.gcube.spatial.data.sdi.model.metadata.MetadataPublishOptions; +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocationBuilder; +import org.gcube.spatial.data.sdi.plugins.SDIAbstractPlugin; +import org.junit.Before; +import org.junit.Test; + +public class MetadataTests { + + String sdiHostname="sdi-t.pre.d4science.org"; + String scope ="/pred4s/preprod/preVRE"; +// +// String sdiHostname="sdi-d-d4s.d4science.org"; +// String scope = "/gcube/devsec/devVRE"; + + @Before + public void setScope(){ + TokenSetter.set(scope); + } + + @Test + public void getAvailableTemplatesTest() throws IllegalArgumentException, URISyntaxException{ + +// Metadata meta=SDIAbstractPlugin.metadata().at(new URI("http://"+sdiHostname+"/sdi-service/gcube/service")).build(); + Metadata meta=SDIAbstractPlugin.metadata().build(); + System.out.println(meta.getAvailableTemplates()); + } + + + @Test + public void pushMetadata() throws IllegalArgumentException, URISyntaxException{ + File toPubilsh=Paths.get("src/test/resources/toEnrichMeta.xml").toFile(); + +// Metadata meta=SDIAbstractPlugin.metadata().at(new URI("http://"+sdiHostname+"/sdi-service/gcube/service")).build(); + Metadata meta=SDIAbstractPlugin.metadata().build(); + System.out.println(meta.pushMetadata(toPubilsh)); + + MetadataPublishOptions opts=new MetadataPublishOptions(new TemplateInvocationBuilder().threddsOnlineResources("my_hostname", "some_dataset.nc", "myPersonalCatalog").get()); + opts.setGeonetworkCategory("service"); + opts.setValidate(false); + System.out.println(meta.pushMetadata(toPubilsh, opts)); + } + + + +} diff --git a/sdi-library/src/test/java/org/gcube/spatial/data/sdi/TokenSetter.java b/sdi-library/src/test/java/org/gcube/spatial/data/sdi/TokenSetter.java new file mode 100644 index 0000000..a6bdb1b --- /dev/null +++ b/sdi-library/src/test/java/org/gcube/spatial/data/sdi/TokenSetter.java @@ -0,0 +1,38 @@ +package org.gcube.spatial.data.sdi; + +import java.util.Properties; + +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; +import org.gcube.common.scope.api.ScopeProvider; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TokenSetter { + + + + private static Properties props=new Properties(); + + static{ + try { + props.load(TokenSetter.class.getResourceAsStream("/tokens.properties")); + } catch (Exception e) { + throw new RuntimeException("YOU NEED TO SET TOKEN FILE IN CONFIGURATION"); + } + } + + + public static void set(String scope){ + try{ + if(!props.containsKey(scope)) throw new RuntimeException("No token found for scope : "+scope); + SecurityTokenProvider.instance.set(props.getProperty(scope)); + }catch(Throwable e){ + log.warn("Unable to set token for scope "+scope,e); + } + ScopeProvider.instance.set(scope); + } + + + +} \ No newline at end of file diff --git a/sdi-library/src/test/java/org/gcube/spatial/data/sdi/utils/RegisterGN.java b/sdi-library/src/test/java/org/gcube/spatial/data/sdi/utils/RegisterGN.java new file mode 100644 index 0000000..c579fdd --- /dev/null +++ b/sdi-library/src/test/java/org/gcube/spatial/data/sdi/utils/RegisterGN.java @@ -0,0 +1,13 @@ +package org.gcube.spatial.data.sdi.utils; + +public class RegisterGN { + + public static void main(String[] args) { + // Get definition + // push to service + + + GeonetworkDefinition + } + +} diff --git a/sdi-library/src/test/resources/toEnrichMeta.xml b/sdi-library/src/test/resources/toEnrichMeta.xml new file mode 100644 index 0000000..8462663 --- /dev/null +++ b/sdi-library/src/test/resources/toEnrichMeta.xml @@ -0,0 +1,298 @@ + + + + a9dfe3b7-6b46-4013-ab1c-313ef2128d31 + + + English + + + UTF-8 + + + Dataset + + + + + fabio.sinibaldi + + + iMarine Consortium + + + Author + + + + + + + iMarine.eu + + + iMarine Consortium + + + + + + +info@i-marine.eu + + + + + + +http://www.i-marine.eu + + +WWW:LINK-1.0-http--link + + +iMarine Consortium site. + + + + + + + Distributor + + + + + + + iMarine Consortium Technical Support + + + iMarine Consortium + + + + + + +support@i-marine.eu + + + + + + +http://www.i-marine.eu + + +WWW:LINK-1.0-http--link + + +iMarine Consortium site. + + + + + + + Resource provider + + + + + 2019-10-02T17:50:11.671+02:00 + + + + + Geometry only + + + + + Surface + + + 0 + + + + + + + + + + + TrueMarble test + + + + +2019-10-02T17:50:11.652+02:00 + + +Creation + + + + + + +a9dfe3b7-6b46-4013-ab1c-313ef2128d31 + + + + + Image digital + + + + + This layer is used as a base layer for GIS VIewer widget + + + This layer is used as a base layer for GIS VIewer widget + + + This layer has been produced by iMarine (www.i-marine.eu). iMarine (283644) is funded by the European Commission under Framework Programme 7 + + + + + As needed + + + + + + + iMarine Consortium + + + True Marble + + + Theme + + + + +General + + + + + 2013-07-04T14:09:55.783+02:00 + + + Creation + + + + + + + + + + + 0.5 + + + + + English + + + environment + + + + + + +true + + +-180.0 + + +180.0 + + +-90.0 + + +90.0 + + + + + + + + + + + + + WMS + + + 1.3.0 + + + + + + + WFS + + + 1.0.0 + + + + + + + WCS + + + 1.0.0 + + + + + + + HTTP + + + 1.0.0 + + + + + + + + + + + + CC-BY-SA + + + License + + + License + + + other restrictions + + + + diff --git a/sdi-service/CHANGELOG.md b/sdi-service/CHANGELOG.md new file mode 100644 index 0000000..ee12e55 --- /dev/null +++ b/sdi-service/CHANGELOG.md @@ -0,0 +1,15 @@ +This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +# Changelog for org.gcube.spatial.data.sdi-service + +## [v1.5.0-SNAPSHOT] 2020-05-15 + + +## [v1.4.3-SNAPSHOT] 2020-05-15 +changed maven repos + +## [v1.4.2] 2020-05-15 + +### Fixes + +- Integration with gcube distribution (https://support.d4science.org/issues/19612) diff --git a/sdi-service/FUNDING.md b/sdi-service/FUNDING.md new file mode 100644 index 0000000..9e48b94 --- /dev/null +++ b/sdi-service/FUNDING.md @@ -0,0 +1,26 @@ +# Acknowledgments + +The projects leading to this software have received funding from a series of European Union programmes including: + +- the Sixth Framework Programme for Research and Technological Development + - [DILIGENT](https://cordis.europa.eu/project/id/004260) (grant no. 004260). +- the Seventh Framework Programme for research, technological development and demonstration + - [D4Science](https://cordis.europa.eu/project/id/212488) (grant no. 212488); + - [D4Science-II](https://cordis.europa.eu/project/id/239019) (grant no.239019); + - [ENVRI](https://cordis.europa.eu/project/id/283465) (grant no. 283465); + - [iMarine](https://cordis.europa.eu/project/id/283644) (grant no. 283644); + - [EUBrazilOpenBio](https://cordis.europa.eu/project/id/288754) (grant no. 288754). +- the H2020 research and innovation programme + - [SoBigData](https://cordis.europa.eu/project/id/654024) (grant no. 654024); + - [PARTHENOS](https://cordis.europa.eu/project/id/654119) (grant no. 654119); + - [EGI-Engage](https://cordis.europa.eu/project/id/654142) (grant no. 654142); + - [ENVRI PLUS](https://cordis.europa.eu/project/id/654182) (grant no. 654182); + - [BlueBRIDGE](https://cordis.europa.eu/project/id/675680) (grant no. 675680); + - [PerformFISH](https://cordis.europa.eu/project/id/727610) (grant no. 727610); + - [AGINFRA PLUS](https://cordis.europa.eu/project/id/731001) (grant no. 731001); + - [DESIRA](https://cordis.europa.eu/project/id/818194) (grant no. 818194); + - [ARIADNEplus](https://cordis.europa.eu/project/id/823914) (grant no. 823914); + - [RISIS 2](https://cordis.europa.eu/project/id/824091) (grant no. 824091); + - [EOSC-Pillar](https://cordis.europa.eu/project/id/857650) (grant no. 857650); + - [Blue Cloud](https://cordis.europa.eu/project/id/862409) (grant no. 862409); + - [SoBigData-PlusPlus](https://cordis.europa.eu/project/id/871042) (grant no. 871042); diff --git a/sdi-service/GeonetworkSE.xml b/sdi-service/GeonetworkSE.xml new file mode 100644 index 0000000..5a77632 --- /dev/null +++ b/sdi-service/GeonetworkSE.xml @@ -0,0 +1,34 @@ + + + 2a3131f6-6ef6-4520-b8bf-70b29c7824f9 + RuntimeResource + + Gis + + geonetwork + 3 + 0 + 5 + 0 + + + node3-d-d4s.d4science.org + READY + + + + http://node3-d-d4s.d4science.org/geonetwork + + + admin + 5jykeFZrlF1Xfa4vohyDYg== + + + + priority + 1 + + + + + diff --git a/sdi-service/LICENSE.md b/sdi-service/LICENSE.md new file mode 100644 index 0000000..3af0507 --- /dev/null +++ b/sdi-service/LICENSE.md @@ -0,0 +1,312 @@ +# European Union Public Licence V. 1.1 + + +EUPL © the European Community 2007 + + +This European Union Public Licence (the “EUPL”) applies to the Work or Software +(as defined below) which is provided under the terms of this Licence. Any use of +the Work, other than as authorised under this Licence is prohibited (to the +extent such use is covered by a right of the copyright holder of the Work). + +The Original Work is provided under the terms of this Licence when the Licensor +(as defined below) has placed the following notice immediately following the +copyright notice for the Original Work: + +Licensed under the EUPL V.1.1 + +or has expressed by any other mean his willingness to license under the EUPL. + + + +## 1. Definitions + +In this Licence, the following terms have the following meaning: + +- The Licence: this Licence. + +- The Original Work or the Software: the software distributed and/or + communicated by the Licensor under this Licence, available as Source Code and + also as Executable Code as the case may be. + +- Derivative Works: the works or software that could be created by the Licensee, + based upon the Original Work or modifications thereof. This Licence does not + define the extent of modification or dependence on the Original Work required + in order to classify a work as a Derivative Work; this extent is determined by + copyright law applicable in the country mentioned in Article 15. + +- The Work: the Original Work and/or its Derivative Works. + +- The Source Code: the human-readable form of the Work which is the most + convenient for people to study and modify. + +- The Executable Code: any code which has generally been compiled and which is + meant to be interpreted by a computer as a program. + +- The Licensor: the natural or legal person that distributes and/or communicates + the Work under the Licence. + +- Contributor(s): any natural or legal person who modifies the Work under the + Licence, or otherwise contributes to the creation of a Derivative Work. + +- The Licensee or “You”: any natural or legal person who makes any usage of the + Software under the terms of the Licence. + +- Distribution and/or Communication: any act of selling, giving, lending, + renting, distributing, communicating, transmitting, or otherwise making + available, on-line or off-line, copies of the Work or providing access to its + essential functionalities at the disposal of any other natural or legal + person. + + + +## 2. Scope of the rights granted by the Licence + +The Licensor hereby grants You a world-wide, royalty-free, non-exclusive, +sub-licensable licence to do the following, for the duration of copyright vested +in the Original Work: + +- use the Work in any circumstance and for all usage, reproduce the Work, modify +- the Original Work, and make Derivative Works based upon the Work, communicate +- to the public, including the right to make available or display the Work or +- copies thereof to the public and perform publicly, as the case may be, the +- Work, distribute the Work or copies thereof, lend and rent the Work or copies +- thereof, sub-license rights in the Work or copies thereof. + +Those rights can be exercised on any media, supports and formats, whether now +known or later invented, as far as the applicable law permits so. + +In the countries where moral rights apply, the Licensor waives his right to +exercise his moral right to the extent allowed by law in order to make effective +the licence of the economic rights here above listed. + +The Licensor grants to the Licensee royalty-free, non exclusive usage rights to +any patents held by the Licensor, to the extent necessary to make use of the +rights granted on the Work under this Licence. + + + +## 3. Communication of the Source Code + +The Licensor may provide the Work either in its Source Code form, or as +Executable Code. If the Work is provided as Executable Code, the Licensor +provides in addition a machine-readable copy of the Source Code of the Work +along with each copy of the Work that the Licensor distributes or indicates, in +a notice following the copyright notice attached to the Work, a repository where +the Source Code is easily and freely accessible for as long as the Licensor +continues to distribute and/or communicate the Work. + + + +## 4. Limitations on copyright + +Nothing in this Licence is intended to deprive the Licensee of the benefits from +any exception or limitation to the exclusive rights of the rights owners in the +Original Work or Software, of the exhaustion of those rights or of other +applicable limitations thereto. + + + +## 5. Obligations of the Licensee + +The grant of the rights mentioned above is subject to some restrictions and +obligations imposed on the Licensee. Those obligations are the following: + +Attribution right: the Licensee shall keep intact all copyright, patent or +trademarks notices and all notices that refer to the Licence and to the +disclaimer of warranties. The Licensee must include a copy of such notices and a +copy of the Licence with every copy of the Work he/she distributes and/or +communicates. The Licensee must cause any Derivative Work to carry prominent +notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes and/or communicates copies of the +Original Works or Derivative Works based upon the Original Work, this +Distribution and/or Communication will be done under the terms of this Licence +or of a later version of this Licence unless the Original Work is expressly +distributed only under this version of the Licence. The Licensee (becoming +Licensor) cannot offer or impose any additional terms or conditions on the Work +or Derivative Work that alter or restrict the terms of the Licence. + +Compatibility clause: If the Licensee Distributes and/or Communicates Derivative +Works or copies thereof based upon both the Original Work and another work +licensed under a Compatible Licence, this Distribution and/or Communication can +be done under the terms of this Compatible Licence. For the sake of this clause, +“Compatible Licence” refers to the licences listed in the appendix attached to +this Licence. Should the Licensee’s obligations under the Compatible Licence +conflict with his/her obligations under this Licence, the obligations of the +Compatible Licence shall prevail. + +Provision of Source Code: When distributing and/or communicating copies of the +Work, the Licensee will provide a machine-readable copy of the Source Code or +indicate a repository where this Source will be easily and freely available for +as long as the Licensee continues to distribute and/or communicate the Work. + +Legal Protection: This Licence does not grant permission to use the trade names, +trademarks, service marks, or names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the copyright notice. + + + +## 6. Chain of Authorship + +The original Licensor warrants that the copyright in the Original Work granted +hereunder is owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each Contributor warrants that the copyright in the modifications he/she brings +to the Work are owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each time You accept the Licence, the original Licensor and subsequent +Contributors grant You a licence to their contributions to the Work, under the +terms of this Licence. + + + +## 7. Disclaimer of Warranty + +The Work is a work in progress, which is continuously improved by numerous +contributors. It is not a finished work and may therefore contain defects or +“bugs” inherent to this type of software development. + +For the above reason, the Work is provided under the Licence on an “as is” basis +and without warranties of any kind concerning the Work, including without +limitation merchantability, fitness for a particular purpose, absence of defects +or errors, accuracy, non-infringement of intellectual property rights other than +copyright as stated in Article 6 of this Licence. + +This disclaimer of warranty is an essential part of the Licence and a condition +for the grant of any rights to the Work. + + + +## 8. Disclaimer of Liability + +Except in the cases of wilful misconduct or damages directly caused to natural +persons, the Licensor will in no event be liable for any direct or indirect, +material or moral, damages of any kind, arising out of the Licence or of the use +of the Work, including without limitation, damages for loss of goodwill, work +stoppage, computer failure or malfunction, loss of data or any commercial +damage, even if the Licensor has been advised of the possibility of such +damage. However, the Licensor will be liable under statutory product liability +laws as far such laws apply to the Work. + + + +## 9. Additional agreements + +While distributing the Original Work or Derivative Works, You may choose to +conclude an additional agreement to offer, and charge a fee for, acceptance of +support, warranty, indemnity, or other liability obligations and/or services +consistent with this Licence. However, in accepting such obligations, You may +act only on your own behalf and on your sole responsibility, not on behalf of +the original Licensor or any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred +by, or claims asserted against such Contributor by the fact You have accepted +any such warranty or additional liability. + + + +## 10. Acceptance of the Licence + +The provisions of this Licence can be accepted by clicking on an icon “I agree” +placed under the bottom of a window displaying the text of this Licence or by +affirming consent in any other similar way, in accordance with the rules of +applicable law. Clicking on that icon indicates your clear and irrevocable +acceptance of this Licence and all of its terms and conditions. + +Similarly, you irrevocably accept this Licence and all of its terms and +conditions by exercising any rights granted to You by Article 2 of this Licence, +such as the use of the Work, the creation by You of a Derivative Work or the +Distribution and/or Communication by You of the Work or copies thereof. + + + +## 11. Information to the public + +In case of any Distribution and/or Communication of the Work by means of +electronic communication by You (for example, by offering to download the Work +from a remote location) the distribution channel or media (for example, a +website) must at least provide to the public the information requested by the +applicable law regarding the Licensor, the Licence and the way it may be +accessible, concluded, stored and reproduced by the Licensee. + + + +## 12. Termination of the Licence + +The Licence and the rights granted hereunder will terminate automatically upon +any breach by the Licensee of the terms of the Licence. + +Such a termination will not terminate the licences of any person who has +received the Work from the Licensee under the Licence, provided such persons +remain in full compliance with the Licence. + + + +## 13. Miscellaneous + +Without prejudice of Article 9 above, the Licence represents the complete +agreement between the Parties as to the Work licensed hereunder. + +If any provision of the Licence is invalid or unenforceable under applicable +law, this will not affect the validity or enforceability of the Licence as a +whole. Such provision will be construed and/or reformed so as necessary to make +it valid and enforceable. + +The European Commission may publish other linguistic versions and/or new +versions of this Licence, so far this is required and reasonable, without +reducing the scope of the rights granted by the Licence. New versions of the +Licence will be published with a unique version number. + +All linguistic versions of this Licence, approved by the European Commission, +have identical value. Parties can take advantage of the linguistic version of +their choice. + + + +## 14. Jurisdiction + +Any litigation resulting from the interpretation of this License, arising +between the European Commission, as a Licensor, and any Licensee, will be +subject to the jurisdiction of the Court of Justice of the European Communities, +as laid down in article 238 of the Treaty establishing the European Community. + +Any litigation arising between Parties, other than the European Commission, and +resulting from the interpretation of this License, will be subject to the +exclusive jurisdiction of the competent court where the Licensor resides or +conducts its primary business. + + + +## 15. Applicable Law + +This Licence shall be governed by the law of the European Union country where +the Licensor resides or has his registered office. + +This licence shall be governed by the Belgian law if: + +- a litigation arises between the European Commission, as a Licensor, and any +- Licensee; the Licensor, other than the European Commission, has no residence +- or registered office inside a European Union country. + + + +## Appendix + + + +“Compatible Licences” according to article 5 EUPL are: + + +- GNU General Public License (GNU GPL) v. 2 + +- Open Software License (OSL) v. 2.1, v. 3.0 + +- Common Public License v. 1.0 + +- Eclipse Public License v. 1.0 + +- Cecill v. 2.0 + diff --git a/sdi-service/README.md b/sdi-service/README.md new file mode 100644 index 0000000..e89c196 --- /dev/null +++ b/sdi-service/README.md @@ -0,0 +1,51 @@ +Spatial Data Infrastucture - Service +-------------------------------------------------- + +SDI-Service is one of the subsystems forming the gCube Spatial Data Infrastructure Facilities. It aims to provide gCube Applications simplified feature in order to manage GeoSpatial Data and Metadata. + +## Built with +* [OpenJDK](https://openjdk.java.net/) - The JDK used +* [JAX-RS](https://github.com/eclipse-ee4j/jaxrs-api) - Java™ API for RESTful Web Services +* [Jersey](https://jersey.github.io/) - JAX-RS runtime +* [Maven](https://maven.apache.org/) - Dependency Management + +## Documentation + +Documentation can be found [here](https://gcube.wiki.gcube-system.org/gcube/SDI-Service). + +## Change log + +See [CHANGELOG.md](CHANGELOG.md). + +## License + +This project is licensed under the EUPL V.1.1 License - see the [LICENSE.md](LICENSE.md) file for details. + +## About the gCube Framework +This software is part of the [gCubeFramework](https://www.gcube-system.org/ "gCubeFramework"): an +open-source software toolkit used for building and operating Hybrid Data +Infrastructures enabling the dynamic deployment of Virtual Research Environments +by favouring the realisation of reuse oriented policies. + +The projects leading to this software have received funding from a series of European Union programmes including: + +- the Sixth Framework Programme for Research and Technological Development + - DILIGENT (grant no. 004260). +- the Seventh Framework Programme for research, technological development and demonstration + - D4Science (grant no. 212488); + - D4Science-II (grant no.239019); + - ENVRI (grant no. 283465); + - iMarine(grant no. 283644); + - EUBrazilOpenBio (grant no. 288754). +- the H2020 research and innovation programme + - SoBigData (grant no. 654024); + - PARTHENOS (grant no. 654119); + - EGIEngage (grant no. 654142); + - ENVRIplus (grant no. 654182); + - BlueBRIDGE (grant no. 675680); + - PerformFish (grant no. 727610); + - AGINFRAplus (grant no. 731001); + - DESIRA (grant no. 818194); + - ARIADNEplus (grant no. 823914); + - RISIS2 (grant no. 824091); + diff --git a/sdi-service/pom.xml b/sdi-service/pom.xml new file mode 100644 index 0000000..17acdf7 --- /dev/null +++ b/sdi-service/pom.xml @@ -0,0 +1,203 @@ + + 4.0.0 + + gcube-sdi-suite + org.gcube.spatial.data + 1.0.0-SNAPSHOT + + org.gcube.spatial.data + sdi-service + 1.5.0-SNPASHOT + SDI Service + REST Interface towards SDI facilities + war + + 2.25.1 + + + scm:git:${gitBaseUrl}/gFeed + scm:git:${gitBaseUrl}/gFeed + ${gitBaseUrl}/gFeed + + + + + org.gcube.distribution + gcube-smartgears-bom + 2.0.0 + pom + import + + + org.glassfish.jersey + jersey-bom + ${jersey.version} + pom + import + + + + + + org.gcube.spatial.data + sdi-interface + + + org.gcube.portlets.user + uri-resolver-manager + [1.0.0, 2.0.0) + + + org.gcube.data.transfer + data-transfer-library + [1.2.0,2.0.0) + + + org.gcube.resources + registry-publisher + + + org.gcube.resourcemanagement + resourcemanager-client + [1.0.0,2.0.0) + + + + org.gcube.core + common-smartgears-app + + + org.gcube.core + common-smartgears + + + + javax.servlet + javax.servlet-api + 3.0.1 + + + javax.ws.rs + javax.ws.rs-api + + + org.glassfish.jersey.containers + jersey-container-servlet + + + javax.transaction + javax.transaction-api + 1.2 + + + org.glassfish.jersey.media + jersey-media-json-jackson + + + org.glassfish.jersey.media + jersey-media-multipart + + + org.glassfish.jersey.ext.cdi + jersey-cdi1x + + + + org.glassfish.jersey.ext.cdi + jersey-weld2-se + + + + + + + + + + it.geosolutions + geonetwork-manager + 1.4-SNAPSHOT + + + org.geotoolkit + geotk-metadata + 3.20 + + + org.w3c + dom + 2.3.0-jaxb-1.0.6 + + + org.geotoolkit + geotk-referencing + 3.20 + + + com.thoughtworks.xstream + xstream + 1.4.9 + + + + org.freemarker + freemarker + 2.3.25-incubating + + + + it.geosolutions + geoserver-manager + 1.5.2 + + + org.slf4j + jcl-over-slf4j + + + + + + ch.qos.logback + logback-classic + test + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-simple + test + + + junit + junit + 4.12 + test + + + + + GeoSolutions-snap + https://nexus.d4science.org/nexus/content/repositories/geo-solutions-snapshots/ + + true + + + false + + + + GeoSolutions-rels + https://nexus.d4science.org/nexus/content/repositories/geo-solutions/ + + false + + + true + + + + GeoToolkit + https://nexus.d4science.org/nexus/content/repositories/geotoolkit/ + + + \ No newline at end of file diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/LocalConfiguration.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/LocalConfiguration.java new file mode 100644 index 0000000..07f3dad --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/LocalConfiguration.java @@ -0,0 +1,119 @@ +package org.gcube.spatial.data.sdi; + +import java.net.URL; +import java.util.Properties; + +import lombok.Synchronized; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class LocalConfiguration { + + //GN + final static public String GEONETWORK_CACHE_TTL="gn.cache.TTL"; + final static public String GEONETWORK_SE_CATEGORY="gn.se.category"; + final static public String GEONETWORK_SE_PLATFORM="gn.se.platform"; + final static public String GEONETWORK_SE_PRIORITY="gn.se.priority"; + final static public String GEONETWORK_SE_ENDPOINT_NAME="gn.se.endpointName"; + + final static public String GEONETWORK_GE_SERVICE_CLASS="gn.ge.serviceClass"; + final static public String GEONETWORK_GE_SERVICE_NAME="gn.ge.serviceName"; + final static public String GEONETWORK_UPDATE_TIMEOUT="gn.update.timeout"; + final static public String GEONETWORK_UPDATE_WAIT="gn.update.wait"; + final static public String GEONETWORK_MAIL="gn.contact.mail"; + final static public String GEONETWORK_PASSWORD_LENGTH="gn.password.length"; + + final static public String GEONETWORK_SE_SUFFIXES="gn.se.suffixes"; + final static public String GEONETWORK_SE_ASSIGNED_SCOPE_PREFIX="gn.se.assigned.scope.prefix"; + final static public String GEONETWORK_SE_SCOPE_USER_PREFIX="gn.se.scope.user.prefix"; + final static public String GEONETWORK_SE_SCOPE_PASSWORD_PREFIX="gn.se.scope.password.prefix"; + final static public String GEONETWORK_SE_CKAN_USER_PREFIX="gn.se.ckan.user.prefix"; + final static public String GEONETWORK_SE_CKAN_PASSWORD_PREFIX="gn.se.ckan.password.prefix"; + final static public String GEONETWORK_SE_MANAGER_USER_PREFIX="gn.se.manager.user.prefix"; + final static public String GEONETWORK_SE_MANAGER_PASSWORD_PREFIX="gn.se.manager.password.prefix"; + final static public String GEONETWORK_SE_DEFAULT_GROUP_PREFIX="gn.se.default.group.prefix"; + final static public String GEONETWORK_SE_SHARED_GROUP_PREFIX="gn.se.shared.group.prefix"; + final static public String GEONETWORK_SE_CONFIDENTIAL_GROUP_PREFIX="gn.se.confidential.group.prefix"; + final static public String GEONETWORK_SE_CONTEXT_GROUP_PREFIX="gn.se.context.group.prefix"; + final static public String GEONETWORK_GROUP_ALL="gn.groups.all"; + final static public String GEONETWORK_GROUP_MAX_LENGTH="gn.groups.max_length"; + + final static public String GEONETWORK_MANDATORY_SG="gn.mandatorySG"; + + + //GS + final static public String GEOSERVER_CACHE_TTL="gs.cache.TTL"; + final static public String GEOSERVER_GE_SERVICE_CLASS="gs.ge.serviceClass"; + final static public String GEOSERVER_GE_SERVICE_NAME="gs.ge.serviceName"; + final static public String GEOSERVER_SE_CATEGORY="gs.se.category"; + final static public String GEOSERVER_SE_PLATFORM="gs.se.platform"; + final static public String GEOSERVER_SE_ENDPOINT_NAME="gs.se.endpointName"; + + public static final String GEOSERVER_HOSTED_LAYERS_TTL="gs.cache.hostedLayers.TTL"; + public static final String GEOSERVER_STYLES_TTL="gs.cache.hostedLayers.TTL"; + public static final String GEOSERVER_WORKSPACE_TTL="gs.cache.hostedLayers.TTL"; + public static final String GEOSERVER_DATASTORE_TTL="gs.cache.hostedLayers.TTL"; + + final static public String GEOSERVER_MANDATORY_SG="gs.mandatorySG"; + + + //TH + final static public String THREDDS_CACHE_TTL="th.cache.TTL"; + final static public String THREDDS_SE_CATEGORY="th.se.category"; + final static public String THREDDS_SE_PLATFORM="th.se.platform"; + final static public String THREDDS_GE_SERVICE_CLASS="th.ge.serviceClass"; + final static public String THREDDS_GE_SERVICE_NAME="th.ge.serviceName"; + final static public String THREDDS_SE_ENDPOINT_NAME="th.se.endpointName"; + + final static public String THREDDS_MANDATORY_SG="th.mandatorySG"; + final static public String THREDDS_SE_REMOTE_MANAGEMENT_ACCESS="th.se.remoteManagement.access"; + + //META + final static public String TEMPLATE_FOLDER="tpl.folder"; + + final static public String TEMPORARY_PERSISTENCE_TTL="temp.ttl"; + + final static public String IS_REGISTRATION_TIMEOUT="is.registration.timeout"; + + static LocalConfiguration instance=null; + + + @Synchronized + public static LocalConfiguration init(URL propertiesURL){ + if(instance==null) + instance=new LocalConfiguration(propertiesURL); + return instance; + } + + private Properties props=new Properties(); + + private LocalConfiguration(URL propertiesURL) { + try{ + log.debug("Loading {} ",propertiesURL); + props.load(propertiesURL.openStream()); + }catch(Exception e){ + throw new RuntimeException(e); + } + } + + public static String getProperty(String property){ + return instance.props.getProperty(property); + } + + public static String getProperty(String property,String defaultValue){ + return instance.props.getProperty(property, defaultValue); + } + + public static Long getTTL(String property) { + return Long.parseLong(getProperty(property)); + } + + public static boolean getFlag(String property) { + return Boolean.parseBoolean(property); + } + + private static Object templateConfiguration=null; + + public static Object getTemplateConfigurationObject() {return templateConfiguration;} + public static void setTemplateConfigurationObject(Object obj) {templateConfiguration=obj;} +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/NetUtils.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/NetUtils.java new file mode 100644 index 0000000..2add166 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/NetUtils.java @@ -0,0 +1,94 @@ +package org.gcube.spatial.data.sdi; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.util.Base64; + +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class NetUtils { + + public static boolean isSameHost(String toTestHost,String toLookForHost) throws UnknownHostException { + log.debug("Checking same hosts {},{}",toTestHost,toLookForHost); + if(toTestHost.equalsIgnoreCase(toLookForHost)) return true; + else { + InetAddress[] toTestHostIPs=InetAddress.getAllByName(toTestHost); + InetAddress[] toLookForHostIPs=InetAddress.getAllByName(toLookForHost); + log.debug("Checking IPs. ToTestIPs {}, ToLookForIPs {} ",toTestHostIPs,toLookForHostIPs); + for(InetAddress toTestIP:toTestHostIPs) { + for(InetAddress toLookForIP:toLookForHostIPs) + if(toTestIP.equals(toLookForIP)) return true; + } + } + log.debug("HOSTS are different."); + return false; + } + + public static String getHostByURL(String url){ + try{ + return new URL(url).getHost(); + }catch(MalformedURLException e) { + log.debug("Passed url {} is invalid. Assuming it's an hostname."); + return url; + } + } + + public static final String getHost(String endpoint) throws MalformedURLException{ + log.debug("Get host from endpoint {} ",endpoint); + if(endpoint.startsWith("http")){ + log.debug("Endpoint seems url.."); + return getHostByURL(endpoint); + } + return endpoint; + } + + + public static boolean isUp(String url) throws IOException { + String finalUrl=resolveRedirects(url); + log.debug("Checking {} availability .. ",finalUrl); + URL urlObj=new URL(finalUrl); + HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection(); + int status=connection.getResponseCode(); + log.trace("HTTP Status response code for {} is {} ",finalUrl,status); + return status>=200&&status<300; + } + + + public static String resolveRedirects(String url) throws IOException{ + log.debug("Resolving redirect for url {} ",url); + URL urlObj=new URL(url); + HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection(); + int status=connection.getResponseCode(); + if(status>=300&&status<400){ + String newUrl=connection.getHeaderField("Location"); + log.debug("Following redirect from {} to {} ",url,newUrl); + return resolveRedirects(newUrl); + }else return url; + } + + + public static void makeAuthorizedCall(String host,String path,String user,String password) throws IOException { + String urlString=String.format("https://%s/%s", host,path); + makeAuthorizedCall(urlString, user, password); + } + + public static void makeAuthorizedCall(String urlString,String user,String password) throws IOException { + log.debug("Connecting to {} ",urlString); + URL url = new URL(urlString); + URLConnection uc = url.openConnection(); + String userpass = user + ":" + password; + String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userpass.getBytes())); + uc.setRequestProperty ("Authorization", basicAuth); + uc.setRequestProperty("gcube-token", SecurityTokenProvider.instance.get()); + InputStream in = uc.getInputStream(); + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/SDIService.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/SDIService.java new file mode 100644 index 0000000..9f1c1cb --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/SDIService.java @@ -0,0 +1,140 @@ +package org.gcube.spatial.data.sdi; + +import java.net.URL; + +import javax.ws.rs.ApplicationPath; + +import org.aopalliance.reflect.Metadata; +import org.gcube.smartgears.ContextProvider; +import org.gcube.smartgears.configuration.container.ContainerConfiguration; +import org.gcube.smartgears.context.application.ApplicationContext; +import org.gcube.spatial.data.sdi.engine.GISManager; +import org.gcube.spatial.data.sdi.engine.GeoNetworkManager; +import org.gcube.spatial.data.sdi.engine.RoleManager; +import org.gcube.spatial.data.sdi.engine.SDIManager; +import org.gcube.spatial.data.sdi.engine.TemplateManager; +import org.gcube.spatial.data.sdi.engine.TemporaryPersistence; +import org.gcube.spatial.data.sdi.engine.ThreddsManager; +import org.gcube.spatial.data.sdi.engine.impl.factories.GeoNetworkManagerFactory; +import org.gcube.spatial.data.sdi.engine.impl.factories.GeoServerManagerFactory; +import org.gcube.spatial.data.sdi.engine.impl.factories.MetadataTemplateManagerFactory; +import org.gcube.spatial.data.sdi.engine.impl.factories.RoleManagerFactory; +import org.gcube.spatial.data.sdi.engine.impl.factories.SDIManagerFactory; +import org.gcube.spatial.data.sdi.engine.impl.factories.TemporaryPersistenceFactory; +import org.gcube.spatial.data.sdi.engine.impl.factories.ThreddsManagerFactory; +import org.gcube.spatial.data.sdi.model.ServiceConstants; +import org.gcube.spatial.data.sdi.rest.GeoNetwork; +import org.gcube.spatial.data.sdi.rest.GeoServer; +import org.gcube.spatial.data.sdi.rest.SDI; +import org.gcube.spatial.data.sdi.rest.Thredds; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.server.ResourceConfig; + +import lombok.extern.slf4j.Slf4j; +@Slf4j +@ApplicationPath(ServiceConstants.APPLICATION) +public class SDIService extends ResourceConfig{ + +// @Inject +// MetadataTemplateManager templateManager; +// @Inject +// TemporaryPersistence persistence; +// + public SDIService() { + super(); + log.warn("Initializing App : Properties.. "); + ApplicationContext context=ContextProvider.get(); + ContainerConfiguration configuration=context.container().configuration(); + try{ + URL resourceUrl = context.application().getResource("/WEB-INF/config.properties"); + LocalConfiguration.init(resourceUrl). + setTemplateConfigurationObject(ContextProvider.get()); + + }catch(Throwable t){ + log.debug("Listing available paths"); + for(Object obj:context.application().getResourcePaths("/WEB-INF")) + log.debug("OBJ : {} ",obj); + + throw new RuntimeException("Unable to load configuration properties",t); + } + + + + packages("org.gcube.spatial.data"); + + + log.warn("Initializing App : Binders"); + + AbstractBinder binder = new AbstractBinder() { + @Override + protected void configure() { + bindFactory(SDIManagerFactory.class).to(SDIManager.class); + bindFactory(GeoNetworkManagerFactory.class).to(GeoNetworkManager.class); + bindFactory(ThreddsManagerFactory.class).to(ThreddsManager.class); + bindFactory(GeoServerManagerFactory.class).to(GISManager.class); + bindFactory(MetadataTemplateManagerFactory.class).to(TemplateManager.class); + bindFactory(RoleManagerFactory.class).to(RoleManager.class); + bindFactory(TemporaryPersistenceFactory.class).to(TemporaryPersistence.class); + + } + }; + register(binder); + + + + register(MultiPartFeature.class); + registerClasses(SDI.class); + registerClasses(GeoNetwork.class); + registerClasses(GeoServer.class); + registerClasses(Thredds.class); + registerClasses(Metadata.class); + + log.warn("Initialization complete"); +// register(MoxyXmlFeature.class); + + + +// String hostName=configuration.hostname(); +// Integer port=configuration.port(); + + + + + + + //SWAGGER +// BeanConfig beanConfig = new BeanConfig(); +// beanConfig.setVersion("1.0.0"); +// beanConfig.setSchemes(new String[]{"http","https"}); +// beanConfig.setHost(hostName+":"+port); +// beanConfig.setBasePath("/gcube/service/"); +// beanConfig.setResourcePackage(GeoNetwork.class.getPackage().getName()); +// beanConfig.setTitle("SDI Service"); +// beanConfig.setDescription("REST Interface towards SDI facilities"); +// beanConfig.setPrettyPrint(true); +// beanConfig.setScan(true); +// +// System.out.println("********************** SDI INIT *****************************"); + + + +// +// log.debug("Initializing persistence manager.. {} :",persistence); +// +// try { +// persistence.init(); +// } catch (Throwable t) { +// throw new RuntimeException("Unabel to init persistence. ",t); +// } +// log.debug("Initializing template manager.. {} : ",templateManager); +// +// ApplicationContext ctx = ContextProvider.get(); +// templateManager.init(ctx); +// + } + + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/SDIServiceLifecycleManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/SDIServiceLifecycleManager.java new file mode 100644 index 0000000..80f41ba --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/SDIServiceLifecycleManager.java @@ -0,0 +1,38 @@ +package org.gcube.spatial.data.sdi; +import javax.xml.bind.annotation.XmlRootElement; + +import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent.Start; +import org.gcube.smartgears.handlers.application.ApplicationLifecycleEvent.Stop; +import org.gcube.smartgears.handlers.application.ApplicationLifecycleHandler; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@XmlRootElement(name = "sdi-lifecycle") +public class SDIServiceLifecycleManager extends ApplicationLifecycleHandler{ + + + + public SDIServiceLifecycleManager() { +// System.out.println("SDI Lifecycle manager created "); +// System.out.println("persistence manager is "+persistence); +// System.out.println("template manager is "+templateManager); +// for(StackTraceElement el:Thread.currentThread().getStackTrace()) +// System.out.println(""+el); + } + + + @Override + public void onStart(Start e) { + super.onStart(e); + + } + + @Override + public void onStop(Stop e) { + super.onStop(e); +// System.out.println("********************** SDI SHUTDOWN *****************************"); +// persistence.shutdown(); + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/SDIServiceManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/SDIServiceManager.java new file mode 100644 index 0000000..0b83310 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/SDIServiceManager.java @@ -0,0 +1,22 @@ +package org.gcube.spatial.data.sdi; + +import org.gcube.smartgears.ApplicationManager; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SDIServiceManager implements ApplicationManager { + + + + @Override + public void onInit() { + + } + + @Override + public void onShutdown() { + + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/GISManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/GISManager.java new file mode 100644 index 0000000..471d95e --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/GISManager.java @@ -0,0 +1,12 @@ +package org.gcube.spatial.data.sdi.engine; + +import org.gcube.spatial.data.sdi.model.service.GeoServerDescriptor; +import org.gcube.spatial.data.sdi.model.services.GeoServerDefinition; + +public interface GISManager extends GeoServiceManager{ + +// public List getConfiguration() throws ConfigurationNotFoundException; +// public ServiceHealthReport getHealthReport(); +// public String registerService(GeoServerDefinition definition)throws ServiceRegistrationException; +// String importHostFromToken(String sourceToken, String hostname) throws ServiceRegistrationException; +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/GeoNetworkManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/GeoNetworkManager.java new file mode 100644 index 0000000..508c857 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/GeoNetworkManager.java @@ -0,0 +1,15 @@ +package org.gcube.spatial.data.sdi.engine; + +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.gn.extension.GeoNetworkClient; +import org.gcube.spatial.data.sdi.model.service.GeoNetworkDescriptor; +import org.gcube.spatial.data.sdi.model.services.GeoNetworkServiceDefinition; + +public interface GeoNetworkManager extends GeoServiceManager{ + + + public GeoNetworkClient getClient() throws ConfigurationNotFoundException; + public GeoNetworkClient getClient(GeoNetworkDescriptor descriptor); + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/GeoServiceManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/GeoServiceManager.java new file mode 100644 index 0000000..7465838 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/GeoServiceManager.java @@ -0,0 +1,19 @@ +package org.gcube.spatial.data.sdi.engine; + +import java.util.List; + +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceRegistrationException; +import org.gcube.spatial.data.sdi.model.health.ServiceHealthReport; +import org.gcube.spatial.data.sdi.model.service.GeoServiceDescriptor; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition; + +public interface GeoServiceManager { + + public T getDescriptorByHostname(String hostname) throws ConfigurationNotFoundException; + public List getAvailableInstances() throws ConfigurationNotFoundException; + public List getSuggestedInstances() throws ConfigurationNotFoundException; + public String registerService(E toRegister) throws ServiceRegistrationException; + public String importHostFromToken(String sourceToken, String hostname) throws ServiceRegistrationException; + public ServiceHealthReport getHealthReport(); +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/RoleManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/RoleManager.java new file mode 100644 index 0000000..ef1a3a6 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/RoleManager.java @@ -0,0 +1,14 @@ +package org.gcube.spatial.data.sdi.engine; + +import java.util.List; + +import org.gcube.spatial.data.sdi.model.credentials.Credentials; +import org.gcube.spatial.data.sdi.model.service.GeoServiceDescriptor; + +public interface RoleManager { + + public Credentials getMostAccessible(List toFilter,boolean considerAdmin); + + public List filterByRole(List toFilter, boolean considerAdmin); + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/SDIManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/SDIManager.java new file mode 100644 index 0000000..57fa104 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/SDIManager.java @@ -0,0 +1,21 @@ +package org.gcube.spatial.data.sdi.engine; + +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceRegistrationException; +import org.gcube.spatial.data.sdi.model.ScopeConfiguration; +import org.gcube.spatial.data.sdi.model.health.HealthReport; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition; + +public interface SDIManager { + + public ScopeConfiguration getContextConfiguration(); + + public HealthReport getHealthReport(); + + public String registerService(ServiceDefinition definition) throws ServiceRegistrationException; + + public String importService(String sourceToken,String host,ServiceDefinition.Type expectedType)throws ServiceRegistrationException; + + public GeoNetworkManager getGeoNetworkManager(); + public ThreddsManager getThreddsManager(); + public GISManager getGeoServerManager(); +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/TemplateManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/TemplateManager.java new file mode 100644 index 0000000..168cfdd --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/TemplateManager.java @@ -0,0 +1,23 @@ +package org.gcube.spatial.data.sdi.engine; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.Set; + +import javax.xml.transform.TransformerException; + +import org.gcube.spatial.data.sdi.engine.impl.metadata.TemplateApplicationReport; +import org.gcube.spatial.data.sdi.model.metadata.TemplateCollection; +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocation; + +public interface TemplateManager { + + + public TemplateCollection getAvailableMetadataTemplates(); + public TemplateApplicationReport applyMetadataTemplates(File original,Set invocations) throws IOException, TransformerException; + public File generateFromTemplate(Map parameters, String templateID) throws Exception; + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/TemporaryPersistence.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/TemporaryPersistence.java new file mode 100644 index 0000000..4331c73 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/TemporaryPersistence.java @@ -0,0 +1,16 @@ +package org.gcube.spatial.data.sdi.engine; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +public interface TemporaryPersistence { + + public void init() throws IOException; + public String store(InputStream is) throws FileNotFoundException, IOException; + public void clean(String id) throws IOException; + public void update(String id, InputStream is) throws FileNotFoundException, IOException; + public File getById(String id) throws FileNotFoundException; + public void shutdown(); +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/ThreddsManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/ThreddsManager.java new file mode 100644 index 0000000..fd1e3b7 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/ThreddsManager.java @@ -0,0 +1,17 @@ +package org.gcube.spatial.data.sdi.engine; + +import java.io.File; + +import org.gcube.data.transfer.model.plugins.thredds.ThreddsCatalog; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ThreddsOperationFault; +import org.gcube.spatial.data.sdi.model.service.ThreddsDescriptor; +import org.gcube.spatial.data.sdi.model.services.ThreddsDefinition; + +public interface ThreddsManager extends GeoServiceManager{ + + public ThreddsCatalog publishCatalog(File catalogFile,String catalogReference) throws ConfigurationNotFoundException, ThreddsOperationFault; + + public ThreddsCatalog createCatalogFromTemplate(String authorityUrl,String catalogPath, + String datasetScanId,String datasetScanName, String subFolder, String catalogReference)throws Exception; +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/AbstractManager.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/AbstractManager.java new file mode 100644 index 0000000..1157af6 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/AbstractManager.java @@ -0,0 +1,51 @@ +package org.gcube.spatial.data.sdi.engine.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.gcube.spatial.data.sdi.engine.GeoServiceManager; +import org.gcube.spatial.data.sdi.engine.impl.cluster.AbstractCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.GeoServiceController; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceRegistrationException; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.health.ServiceHealthReport; +import org.gcube.spatial.data.sdi.model.service.GeoServiceDescriptor; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition; + +public abstract class AbstractManager> implements GeoServiceManager{ + + + protected abstract ISModule getRetriever(); + protected abstract AbstractCluster getCluster(); + + @Override + public T getDescriptorByHostname(String hostname) throws ConfigurationNotFoundException { + return getCluster().getControllerByHostName(hostname).getDescriptor(); + } + + @Override + public List getAvailableInstances() throws ConfigurationNotFoundException { + ArrayList toReturn=new ArrayList<>(); + for(L controller :getCluster().getActualCluster()) + toReturn.add(controller.getDescriptor()); + return toReturn; + } + + + @Override + public String registerService(E toRegister) throws ServiceRegistrationException { + return getRetriever().registerService(toRegister); + } + + @Override + public String importHostFromToken(String sourceToken, String hostname) throws ServiceRegistrationException { + return getRetriever().importHostFromToken(sourceToken, hostname); + } + + @Override + public ServiceHealthReport getHealthReport() { + return getRetriever().getHealthReport(); + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/GISManagerImpl.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/GISManagerImpl.java new file mode 100644 index 0000000..bef3690 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/GISManagerImpl.java @@ -0,0 +1,44 @@ +package org.gcube.spatial.data.sdi.engine.impl; + +import java.util.List; + +import javax.inject.Singleton; + +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.GISManager; +import org.gcube.spatial.data.sdi.engine.impl.cluster.AbstractCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.GeoServerCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.GeoServerController; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.is.GeoServerClusterRetriever; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.service.GeoServerDescriptor; +import org.gcube.spatial.data.sdi.model.services.GeoServerDefinition; + +@Singleton +public class GISManagerImpl extends AbstractManager implements GISManager{ + + private GeoServerClusterRetriever retriever=null; + private GeoServerCluster cluster=null; + + public GISManagerImpl() { + retriever=new GeoServerClusterRetriever(); + cluster=new GeoServerCluster(LocalConfiguration.getTTL(LocalConfiguration.GEOSERVER_CACHE_TTL), retriever, "GeoServer - cache"); + } + + @Override + protected AbstractCluster getCluster() { + return cluster; + } + + @Override + protected ISModule getRetriever() { + return retriever; + } + @Override + public List getSuggestedInstances() throws ConfigurationNotFoundException { + return getAvailableInstances(); + } + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/GeoNetworkManagerImpl.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/GeoNetworkManagerImpl.java new file mode 100644 index 0000000..0a03f11 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/GeoNetworkManagerImpl.java @@ -0,0 +1,69 @@ +package org.gcube.spatial.data.sdi.engine.impl; + +import java.util.Collections; +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.GeoNetworkManager; +import org.gcube.spatial.data.sdi.engine.RoleManager; +import org.gcube.spatial.data.sdi.engine.impl.cluster.AbstractCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.GeoNetworkCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.GeoNetworkController; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.gn.extension.GeoNetworkClient; +import org.gcube.spatial.data.sdi.engine.impl.is.GeoNetworkRetriever; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.credentials.Credentials; +import org.gcube.spatial.data.sdi.model.service.GeoNetworkDescriptor; +import org.gcube.spatial.data.sdi.model.services.GeoNetworkServiceDefinition; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Singleton +public class GeoNetworkManagerImpl extends AbstractManager implements GeoNetworkManager { + + RoleManager roleManager; + + + private GeoNetworkRetriever retriever=null; + private GeoNetworkCluster cluster=null; + + @Inject + public GeoNetworkManagerImpl(RoleManager roleManager) { + this.roleManager=roleManager; + retriever=new GeoNetworkRetriever(); + cluster=new GeoNetworkCluster(LocalConfiguration.getTTL(LocalConfiguration.GEONETWORK_CACHE_TTL), retriever, "GeoNEtwork - cache"); + } + + + @Override + protected AbstractCluster getCluster() { + return cluster; + } + + @Override + protected ISModule getRetriever() { + return retriever; + } + + @Override + public List getSuggestedInstances() throws ConfigurationNotFoundException { + return Collections.singletonList(getCluster().getDefaultController().getDescriptor()); + } + + @Override + public GeoNetworkClient getClient() throws ConfigurationNotFoundException { + return getClient(getCluster().getDefaultController().getDescriptor()); + } + + @Override + public GeoNetworkClient getClient(GeoNetworkDescriptor descriptor) { + Credentials selected=roleManager.getMostAccessible(descriptor.getAccessibleCredentials(), false); + log.info("Logging in {} using {} ",descriptor,selected); + return new GeoNetworkClient(descriptor.getBaseEndpoint(), descriptor.getVersion(), selected.getPassword(), selected.getUsername(),descriptor); + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/RoleManagerImpl.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/RoleManagerImpl.java new file mode 100644 index 0000000..59aadca --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/RoleManagerImpl.java @@ -0,0 +1,55 @@ +package org.gcube.spatial.data.sdi.engine.impl; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Singleton; + +import org.gcube.spatial.data.sdi.engine.RoleManager; +import org.gcube.spatial.data.sdi.model.credentials.AccessType; +import org.gcube.spatial.data.sdi.model.credentials.Credentials; +import org.gcube.spatial.data.sdi.model.service.GeoServiceDescriptor; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Singleton +public class RoleManagerImpl implements RoleManager { + + public RoleManagerImpl() { + // TODO Auto-generated constructor stub + } + + @Override + public Credentials getMostAccessible(List toFilter, boolean considerAdmin) { + + //need to check roles by contacting social + AccessType maxLevel=getMaxLevel(considerAdmin); + + Credentials toReturn=null; + for(Credentials cred: toFilter) { + if(cred.getAccessType().compareTo(maxLevel)>=0) { // cred level + if(toReturn==null || cred.getAccessType().compareTo(toReturn.getAccessType())<0) + toReturn = cred; + } + } + return toReturn; + } + + @Override + public List filterByRole(List toFilter, boolean considerAdmin) { + ArrayList toReturn=new ArrayList(); + AccessType maxLevel=getMaxLevel(considerAdmin); + for(T descriptor:toFilter) { + + } + return toReturn; + } + + + private AccessType getMaxLevel(boolean considerAdmin) { + //TOD ask to social manager + return considerAdmin?AccessType.ADMIN:AccessType.CONTEXT_MANAGER; + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/SDIManagerImpl.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/SDIManagerImpl.java new file mode 100644 index 0000000..78ef233 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/SDIManagerImpl.java @@ -0,0 +1,158 @@ +package org.gcube.spatial.data.sdi.engine.impl; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.gcube.spatial.data.sdi.engine.GISManager; +import org.gcube.spatial.data.sdi.engine.GeoNetworkManager; +import org.gcube.spatial.data.sdi.engine.SDIManager; +import org.gcube.spatial.data.sdi.engine.ThreddsManager; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceDefinitionException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceRegistrationException; +import org.gcube.spatial.data.sdi.model.ScopeConfiguration; +import org.gcube.spatial.data.sdi.model.health.HealthReport; +import org.gcube.spatial.data.sdi.model.health.Level; +import org.gcube.spatial.data.sdi.model.health.ServiceHealthReport; +import org.gcube.spatial.data.sdi.model.services.GeoNetworkServiceDefinition; +import org.gcube.spatial.data.sdi.model.services.GeoServerDefinition; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition; +import org.gcube.spatial.data.sdi.model.services.ThreddsDefinition; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; + +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +@Singleton +public class SDIManagerImpl implements SDIManager { + + GeoNetworkManager geonetworkManager; + ThreddsManager threddsManager; + GISManager gisManager; + + + @Inject + public SDIManagerImpl(GeoNetworkManager geonetworkManager, ThreddsManager threddsManager, GISManager gisManager) { + super(); + this.geonetworkManager = geonetworkManager; + this.threddsManager = threddsManager; + this.gisManager = gisManager; + } + + + + + + @Override + public ScopeConfiguration getContextConfiguration() { + + // TODO filter info by user role + + ScopeConfiguration toReturn=new ScopeConfiguration(); + toReturn.setContextName(ScopeUtils.getCurrentScopeName()); + try{ + toReturn.setGeonetworkConfiguration(geonetworkManager.getSuggestedInstances()); + }catch(Exception e){ + log.warn("Scope is not well configured. Missing GeoNetwork. ",e); + } + + try{ + toReturn.setThreddsConfiguration(threddsManager.getSuggestedInstances()); + }catch(Exception e){ + log.warn("THREDDS not found in current scope {} ",ScopeUtils.getCurrentScope()); + } + + try{ + toReturn.setGeoserverClusterConfiguration(gisManager.getSuggestedInstances()); + }catch(Exception e){ + log.warn("GeoServer not found in current scope {} ",ScopeUtils.getCurrentScope()); + } + + return toReturn; + } + + + @Override + public String toString() { + // TODO Auto-generated method stub + return super.toString(); + } + + @Override + public HealthReport getHealthReport() { + HealthReport report=new HealthReport(); + report.setContext(ScopeUtils.getCurrentScope()); + ServiceHealthReport threddsReport=threddsManager.getHealthReport(); + report.setThredds(threddsReport); + ServiceHealthReport gnReport=geonetworkManager.getHealthReport(); + report.setGeonetwork(gnReport); + ServiceHealthReport gsReport=gisManager.getHealthReport(); + report.setGeoserverCluster(gsReport); + + Level overall=Level.OK; + if(threddsReport.getOverallStatus().equals(Level.ERROR)|| + gnReport.getOverallStatus().equals(Level.ERROR)|| + gsReport.getOverallStatus().equals(Level.ERROR)) overall=Level.ERROR; + else if(threddsReport.getOverallStatus().equals(Level.WARNING)|| + gnReport.getOverallStatus().equals(Level.WARNING)|| + gsReport.getOverallStatus().equals(Level.WARNING)) overall=Level.WARNING; + + report.setOverallStatus(overall); + log.debug("Returning report : {} ",report); + return report; + } + + + @Override + public String registerService(ServiceDefinition definition) throws ServiceRegistrationException{ + try { + + switch(definition.getType()) { + case GEONETWORK : + return geonetworkManager.registerService((GeoNetworkServiceDefinition)definition); + + case GEOSERVER : + return gisManager.registerService((GeoServerDefinition)definition); + + case THREDDS : + return threddsManager.registerService((ThreddsDefinition)definition); + + default : throw new InvalidServiceDefinitionException("Unable to register. Invalid service type. Definition was "+definition); + } + }catch(ClassCastException e) { + throw new InvalidServiceDefinitionException("Unable to register. Incoherent service type. Definition was "+definition); + } + } + + @Override + public String importService(String sourceToken, String host, ServiceDefinition.Type expectedType) throws ServiceRegistrationException { + switch(expectedType) { + case GEONETWORK : + return geonetworkManager.importHostFromToken(sourceToken, host); + + case GEOSERVER : + return gisManager.importHostFromToken(sourceToken, host); + + case THREDDS : + return threddsManager.importHostFromToken(sourceToken, host); + + default : throw new InvalidServiceDefinitionException("Unable to register. Invalid service type "+expectedType); + } + } + + + @Override + public GeoNetworkManager getGeoNetworkManager() { + return geonetworkManager; + } + + @Override + public GISManager getGeoServerManager() { + return gisManager; + } + + @Override + public ThreddsManager getThreddsManager() { + return threddsManager; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/TemporaryPersistenceImpl.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/TemporaryPersistenceImpl.java new file mode 100644 index 0000000..4dbf28c --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/TemporaryPersistenceImpl.java @@ -0,0 +1,178 @@ +package org.gcube.spatial.data.sdi.engine.impl; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.UUID; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Singleton; + +import org.apache.commons.io.IOUtils; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.TemporaryPersistence; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Singleton +public class TemporaryPersistenceImpl implements TemporaryPersistence { + + private final static String UPLOADING_FILE_SUFFIX=".part"; + + private final static FileFilter TO_CHECK_FILES_FILTER=new FileFilter() { + + @Override + public boolean accept(File pathname) { + return !pathname.isDirectory()&&!pathname.getName().endsWith(UPLOADING_FILE_SUFFIX); + } + }; + + + // *************** CHECKER THREAD + + @AllArgsConstructor + private static class CleanUpThread implements Runnable{ + private Long TTL; + private File persistenceLocation; + private FileFilter toCheckFiles; + + + @Override + public void run() { + try{ + log.debug("Executing cleanup.."); + long count=0l; + for(File found:persistenceLocation.listFiles(toCheckFiles)) + if(found.lastModified()-System.currentTimeMillis()>=TTL){ + try{ + Files.delete(found.toPath()); + }catch(Throwable t){ + log.warn("Unable to delete {} ",found.getAbsolutePath(),t); + } + } + log.debug("Cleaned up {} files.",count); + }catch(Throwable t){ + log.error("Unexpected error.",t); + } + } + } + + + // private static TemporaryPersistenceImpl singleton=null; + + // *************** INSTANCE LOGIC + + private File persistenceLocation=null; + + private ScheduledExecutorService service=null; + + + + @Override + @PostConstruct + public void init() { + try { + persistenceLocation=Files.createTempDirectory("SDI").toFile(); + System.out.println("************************************** TEMPORARY PERSISTENCE INIT **************************"); + System.out.println("SDI-Service - Temporary persistence location is "+persistenceLocation.getAbsolutePath()); + System.out.println("**************************************"); + + log.trace("Temporary persistence is "+persistenceLocation.getAbsolutePath()); + + // init check thread + service = new ScheduledThreadPoolExecutor (1); + + + long TTL=Long.parseLong(LocalConfiguration.getProperty(LocalConfiguration.TEMPORARY_PERSISTENCE_TTL, "120000")); + log.debug("Temp TTL is {} ",TTL); + long delay=TTL/4; + + service.scheduleWithFixedDelay(new CleanUpThread(TTL, persistenceLocation, TO_CHECK_FILES_FILTER), delay, delay, TimeUnit.MILLISECONDS); + }catch(Throwable t) { + throw new RuntimeException("Unable to init persistence ",t); + } + } + + @Override + public File getById(String id) throws FileNotFoundException { + File toReturn=new File(persistenceLocation,id); + if(!toReturn.exists()) throw new FileNotFoundException(); + return toReturn; + } + + @Override + public String store(InputStream is) throws FileNotFoundException, IOException { + String partUUID=getUUID()+".part"; + log.debug("Storing file "+partUUID); + File created=transferStream(is, new File(persistenceLocation,partUUID)); + String toReturn=created.getName().substring(0, created.getName().lastIndexOf(".")-1); + created.renameTo(new File(persistenceLocation,toReturn)); + log.debug("Completed. Part renamed to "+toReturn); + return toReturn; + } + + @Override + @PreDestroy + public void clean(String id){ + try{ + System.out.println("*************************************** TEMPORARY PERSISTENCE PRE DESTROY ******************************"); + Files.delete(Paths.get(persistenceLocation.getAbsolutePath(), id)); + }catch(Throwable t) { + throw new RuntimeException("Unable to clean up temporary persistence. ",t); + } + } + + @Override + public void shutdown() { + log.debug("Shutting down persistence.."); + service.shutdownNow(); + log.debug("Clearing persistence folder.."); + for(File f:persistenceLocation.listFiles()) + try{ + if(!f.delete()) f.deleteOnExit(); + }catch(Throwable t){ + log.warn("Exception while clearing persistence.. ",t); + } + } + + @Override + public void update(String id, InputStream is) throws FileNotFoundException, IOException { + File toUpdate=getById(id); + transferStream(is,toUpdate); + } + + private static File transferStream(InputStream in, File destination) throws FileNotFoundException, IOException{ + + FileOutputStream out=null; + try{ + ; + out=new FileOutputStream(destination,false); + + int read = 0; + byte[] bytes = new byte[1024]; + + while ((read = in.read(bytes)) != -1) { + out.write(bytes, 0, read); + } + out.flush(); + return destination; + }finally{ + if(out!=null) IOUtils.closeQuietly(out); + } + } + + private static String getUUID(){ + return UUID.randomUUID().toString().replace(" ", "_"); + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/ThreddsManagerImpl.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/ThreddsManagerImpl.java new file mode 100644 index 0000000..d9a2854 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/ThreddsManagerImpl.java @@ -0,0 +1,87 @@ +package org.gcube.spatial.data.sdi.engine.impl; + +import java.io.File; +import java.util.HashMap; +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.gcube.data.transfer.model.plugins.thredds.ThreddsCatalog; +import org.gcube.data.transfer.model.plugins.thredds.ThreddsInfo; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.TemplateManager; +import org.gcube.spatial.data.sdi.engine.ThreddsManager; +import org.gcube.spatial.data.sdi.engine.impl.cluster.AbstractCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.ThreddsCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.ThreddsController; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ThreddsOperationFault; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.engine.impl.is.ThreddsRetriever; +import org.gcube.spatial.data.sdi.engine.impl.metadata.GenericTemplates; +import org.gcube.spatial.data.sdi.model.service.ThreddsDescriptor; +import org.gcube.spatial.data.sdi.model.services.ThreddsDefinition; + +import lombok.extern.slf4j.Slf4j; + +@Singleton +@Slf4j +public class ThreddsManagerImpl extends AbstractManager implements ThreddsManager { + + private ThreddsCluster cluster=null; + + private ThreddsRetriever retriever=null; + + private TemplateManager templateManager=null; + + + @Inject + public ThreddsManagerImpl(TemplateManager templateManager) { + retriever=new ThreddsRetriever(); + cluster=new ThreddsCluster(LocalConfiguration.getTTL(LocalConfiguration.THREDDS_CACHE_TTL),retriever,"Thredds Cache"); + this.templateManager=templateManager; + } + + @Override + protected AbstractCluster getCluster() { + return cluster; + } + + @Override + protected ISModule getRetriever() { + return retriever; + } + @Override + public List getSuggestedInstances() throws ConfigurationNotFoundException { + return getAvailableInstances(); + } + + + @Override + public ThreddsCatalog publishCatalog(File catalogFile, String catalogReference) throws ConfigurationNotFoundException, ThreddsOperationFault { + return getCluster().getDefaultController().publishCatalog(catalogFile, catalogReference); + } + + @Override + public ThreddsCatalog createCatalogFromTemplate(String authorityUrl, String catalogPath, String datasetScanId, + String datasetScanName, String subFolder, String catalogReference) throws Exception { + ThreddsController controller=getCluster().getDefaultController(); + ThreddsInfo info=controller.getThreddsInfo(); + + + log.info("Going to create catalog for authorityURL {}, path {}, subFolder {} ",authorityUrl,catalogPath,subFolder); + + HashMap parameters=new HashMap(); + parameters.put(GenericTemplates.ThreddsCatalogTemplate.AUTHORITY_URL, authorityUrl); + parameters.put(GenericTemplates.ThreddsCatalogTemplate.CATALOG_PATH, catalogPath); + parameters.put(GenericTemplates.ThreddsCatalogTemplate.DATASET_SCAN_ID, datasetScanId); + parameters.put(GenericTemplates.ThreddsCatalogTemplate.DATASET_SCAN_NAME, datasetScanName); + parameters.put(GenericTemplates.ThreddsCatalogTemplate.LOCATION, info.getLocalBasePath()+"/"+subFolder); + + File catalog= + templateManager.generateFromTemplate(parameters, GenericTemplates.ThreddsCatalogTemplate.FILENAME); + + return controller.publishCatalog(catalog, catalogReference); + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/AbstractCluster.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/AbstractCluster.java new file mode 100644 index 0000000..3445408 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/AbstractCluster.java @@ -0,0 +1,100 @@ +package org.gcube.spatial.data.sdi.engine.impl.cluster; + +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.concurrent.ConcurrentHashMap; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; +import org.gcube.spatial.data.sdi.NetUtils; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.is.CachedObject; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.service.GeoServiceDescriptor; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractCluster> { + + private long objectsTTL; + private ConcurrentHashMap>> scopedCache; + private ISModule retriever; + private String cacheName; + + + public synchronized ArrayList getActualCluster() throws ConfigurationNotFoundException{ + String key=ScopeUtils.getCurrentScope(); + log.info("Getting object from cache{} , key is {} ",cacheName,key); + if((!scopedCache.containsKey(key))||(!scopedCache.get(key).isValid(objectsTTL))) + scopedCache.put(key, new CachedObject>(getLiveControllerCollection())); + return scopedCache.get(key).getTheObject(); + } + + + protected ArrayList getLiveControllerCollection() throws ConfigurationNotFoundException{ + ArrayList toReturn=new ArrayList(); + for(ServiceEndpoint endpoint : retriever.getISInformation()) + try { + toReturn.add(translate(endpoint)); + }catch(Throwable t) { + log.warn("Unable to handle ServiceEndpoint [name {} , ID {}]",endpoint.profile().name(),endpoint.id(),t); + } + Comparator comp=getComparator(); + if(comp!=null)Collections.sort(toReturn, getComparator()); + return toReturn; + } + + protected abstract E translate(ServiceEndpoint e) throws InvalidServiceEndpointException; + + + + + public void invalidate(){ + String key=ScopeUtils.getCurrentScope(); + log.info("Invalidating cache {} under scope {} ",cacheName,key); + if(scopedCache.containsKey(key))scopedCache.get(key).invalidate(); + } + + public void invalidateAll(){ + for(CachedObject obj:scopedCache.values())obj.invalidate(); + } + + + public E getDefaultController() throws ConfigurationNotFoundException { + return getActualCluster().get(0); + } + + protected abstract Comparator getComparator(); + + + public E getControllerByHostName(String hostname) throws ConfigurationNotFoundException { + ArrayList controllerCluster=getLiveControllerCollection(); + log.debug("Looking for {} inside cluster [size = {}]",hostname,controllerCluster.size()); + for(E toCheck:controllerCluster) { + String toCheckHostname=NetUtils.getHostByURL(toCheck.getDescriptor().getBaseEndpoint()); + try { + if(NetUtils.isSameHost(toCheckHostname, hostname)) + return toCheck; + } catch (UnknownHostException e) { + log.warn("Unable to check equality between {} and {} hosts.",toCheckHostname,hostname,e); + } + } + return null; + } + + public AbstractCluster(long objectsTTL, ISModule retriever, String cacheName) { + super(); + this.objectsTTL = objectsTTL; + this.retriever = retriever; + this.cacheName=cacheName; + scopedCache=new ConcurrentHashMap<>(); + } + + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoNetworkCluster.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoNetworkCluster.java new file mode 100644 index 0000000..42e0911 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoNetworkCluster.java @@ -0,0 +1,52 @@ +package org.gcube.spatial.data.sdi.engine.impl.cluster; + +import java.util.ArrayList; +import java.util.Comparator; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceInteractionException; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.service.GeoNetworkDescriptor; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GeoNetworkCluster extends AbstractCluster{ + + private static final Comparator comparator=new Comparator() { + @Override + public int compare(GeoNetworkController o1, GeoNetworkController o2) { + return o1.getPriority().compareTo(o2.getPriority()); + } + }; + + + public GeoNetworkCluster(long objectsTTL, ISModule retriever, String cacheName) { + super(objectsTTL, retriever, cacheName); + // TODO Auto-generated constructor stub + } + + @Override + protected Comparator getComparator() { + return comparator; + } + + @Override + protected GeoNetworkController translate(ServiceEndpoint e) throws InvalidServiceEndpointException { + return new GeoNetworkController(e); + } + + @Override + protected ArrayList getLiveControllerCollection() throws ConfigurationNotFoundException { + ArrayList toReturn= super.getLiveControllerCollection(); + for(GeoNetworkController controller:toReturn) + try{ + controller.configure(); + }catch(ServiceInteractionException e) { + log.warn("Unexpected exception while configuring GeoNetwork SE [ID : "+controller.getServiceEndpoint().id()+"]",e); + } + return toReturn; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoNetworkController.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoNetworkController.java new file mode 100644 index 0000000..8d11ed5 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoNetworkController.java @@ -0,0 +1,339 @@ +package org.gcube.spatial.data.sdi.engine.impl.cluster; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.Property; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.faults.OutdatedServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceInteractionException; +import org.gcube.spatial.data.sdi.engine.impl.gn.extension.GeoNetworkClient; +import org.gcube.spatial.data.sdi.engine.impl.gn.extension.GeoNetworkUtils; +import org.gcube.spatial.data.sdi.engine.impl.gn.utils.UserUtils; +import org.gcube.spatial.data.sdi.engine.impl.is.ISUtils; +import org.gcube.spatial.data.sdi.model.credentials.AccessType; +import org.gcube.spatial.data.sdi.model.credentials.Credentials; +import org.gcube.spatial.data.sdi.model.gn.Group; +import org.gcube.spatial.data.sdi.model.gn.User; +import org.gcube.spatial.data.sdi.model.service.GeoNetworkDescriptor; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GeoNetworkController extends GeoServiceController{ + + + private static String scopeUserPrefix=null; + private static String scopePasswordPrefix=null; + private static String ckanUserPrefix=null; + private static String ckanPasswordPrefix=null; + private static String managerUserPrefix=null; + private static String managerPasswordPrefix=null; + private static String assignedScopePrefix=null; + private static String defaultGroupPrefix=null; + private static String sharedGroupPrefix=null; + private static String confidentialGroupPrefix=null; + private static String contextGroupPrefix=null; + private static String suffixesProperty=null; + private static String priorityProperty=null; + + static{ + + scopeUserPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_SCOPE_USER_PREFIX); + scopePasswordPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_SCOPE_PASSWORD_PREFIX); + ckanUserPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_CKAN_USER_PREFIX); + ckanPasswordPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_CKAN_PASSWORD_PREFIX); + managerUserPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_MANAGER_USER_PREFIX); + managerPasswordPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_MANAGER_PASSWORD_PREFIX); + assignedScopePrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_ASSIGNED_SCOPE_PREFIX); + defaultGroupPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_DEFAULT_GROUP_PREFIX); + sharedGroupPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_SHARED_GROUP_PREFIX); + confidentialGroupPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_CONFIDENTIAL_GROUP_PREFIX); + contextGroupPrefix=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_CONTEXT_GROUP_PREFIX); + suffixesProperty=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_SUFFIXES); + priorityProperty=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_PRIORITY); + + } + + private String suffixes; + private Integer priority; + + + public Integer getPriority() { + return priority; + } + + + public GeoNetworkController(ServiceEndpoint serviceEndpoint) throws InvalidServiceEndpointException { + super(serviceEndpoint); + } + + + @Override + protected void setServiceEndpoint(ServiceEndpoint toSet) { + super.setServiceEndpoint(toSet); + suffixes=getSEProperty(suffixesProperty, true); + priority=Integer.parseInt(getSEProperty(priorityProperty, true)); + } + + + @Override + protected GeoNetworkDescriptor getLiveDescriptor(){ + GeoNetworkDescriptor descriptor=new GeoNetworkDescriptor(); + descriptor.setBaseEndpoint(baseURL); + descriptor.setVersion(version); + String currentScopeName=ScopeUtils.getCurrentScopeName(); + + String suffix=getSuffixByScope(currentScopeName); + + + ArrayList availableCredentials=new ArrayList(); + availableCredentials.add(adminAccount); + + Credentials context=new Credentials(getSEProperty(scopeUserPrefix+suffix, true), + getSEProperty(scopePasswordPrefix+suffix, true), AccessType.CONTEXT_USER); + availableCredentials.add(context); + + Credentials ckan=new Credentials(getSEProperty(ckanUserPrefix+suffix, true), + getSEProperty(ckanPasswordPrefix+suffix, true), AccessType.CKAN); + availableCredentials.add(ckan); + + String managerUser=getSEProperty(managerUserPrefix+suffix, false); + if(managerUser!=null) { + Credentials manager=new Credentials(managerUser,getSEProperty(managerPasswordPrefix+suffix, true),AccessType.CONTEXT_MANAGER); + availableCredentials.add(manager); + } + + descriptor.setAccessibleCredentials(availableCredentials); + + descriptor.setPriority(priority); + + + descriptor.setContextGroup(getSEProperty(contextGroupPrefix+suffix, true)); + descriptor.setSharedGroup(getSEProperty(sharedGroupPrefix+suffix, true)); + String confidentialGroup=getSEProperty(confidentialGroupPrefix+suffix, false); + if(confidentialGroup!=null) + descriptor.setConfidentialGroup(confidentialGroup); + + + descriptor.setDefaultGroup(getSEProperty(defaultGroupPrefix+suffix, true)); + descriptor.setPublicGroup(LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_GROUP_ALL)); + + return descriptor; + } + + @Override + protected AccessPoint getTheRightAccessPoint(ServiceEndpoint endpoint) { + for(AccessPoint declaredPoint:endpoint.profile().accessPoints().asCollection()) { + if(declaredPoint.name().equals(LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_SE_ENDPOINT_NAME))) { + return declaredPoint; + } + } + return null; + } + + + @Override + protected void initServiceEndpoint() throws OutdatedServiceEndpointException, ServiceInteractionException { + String scopeName=ScopeUtils.getCurrentScopeName(); + + try { + if(getSuffixByScope(scopeName)==null) throw new InvalidServiceEndpointException("Scope not present in resource"); + }catch(InvalidServiceEndpointException e) { + insertScopeInfo(ScopeUtils.getCurrentScope()); + } + + } + + + private void insertScopeInfo(String scope) throws OutdatedServiceEndpointException, ServiceInteractionException { + + String scopeName=ScopeUtils.getScopeName(scope); + + log.info("Creating scope {} configuration for GeoNetwork at {} ",scopeName,baseURL); + //Get GN Client + log.debug("Instantiating client as admin.."); + GeoNetworkClient gnClient=new GeoNetworkClient(baseURL,version,adminAccount.getPassword(),adminAccount.getUsername()); + log.debug("Getting Users and groups from instance.."); + Set existingGroups=gnClient.getGroups(); + Set existingUsers=gnClient.getUsers(); + + // Get parent scopes users and groups + // configure parent [mng,ctx] to access [sh] + // configure siblings [mng,ctx] to access [sh] + // configure users [mng,ctx] to access siblings [sh] and parent [ctx,sh] + + ArrayList sharedGroupExternalUsers=new ArrayList(); + ArrayList externalGroupsToAccess=new ArrayList(); + + // gathering users and groups from siblings + log.debug("Getting Siblings information from SE.."); + for(String siblingScope:ISUtils.getSiblingsScopesInResource(serviceEndpoint, scope)) + try { + getSuffixByScope(ScopeUtils.getScopeName(siblingScope)); + for(String username:getUserNamesByScope(siblingScope, true, true, false)) + sharedGroupExternalUsers.add(UserUtils.getByName(existingUsers, username)); + + externalGroupsToAccess.addAll(getGroupIDSByScope(siblingScope, true, false, false)); + }catch(InvalidServiceEndpointException e) { + log.debug("Sibling scope {} not found in resource. Skipping.",siblingScope); + } + + log.debug("Getting Parents information from SE.."); + // gathering users and groups from parents + for(String parentScope:ScopeUtils.getParentScopes(scope)) + try { + getSuffixByScope(ScopeUtils.getScopeName(parentScope)); + for(String username:getUserNamesByScope(parentScope, true, true, false)) + sharedGroupExternalUsers.add(UserUtils.getByName(existingUsers, username)); + + externalGroupsToAccess.addAll(getGroupIDSByScope(parentScope, true, true, false)); + }catch(InvalidServiceEndpointException e) { + log.debug("Parent scope {} not found in resource. Skipping it. ",parentScope); + } + + + + // Creating groups + + log.debug("Creating groups.."); + String contactMail=LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_MAIL); + int passwordLength=Integer.parseInt(LocalConfiguration.getProperty(LocalConfiguration.GEONETWORK_PASSWORD_LENGTH, "10")); + + // create user & groups [sh,conf,ctx] + Group shared=GeoNetworkUtils.generateGroup(existingGroups, "Shared_"+scopeName, "Shared metadata group for "+scopeName, contactMail); + shared=gnClient.createGroup(shared); + existingGroups.add(shared); + + Group context=GeoNetworkUtils.generateGroup(existingGroups, "Context_"+scopeName, "Context metadata group for "+scopeName, contactMail); + context=gnClient.createGroup(context); + existingGroups.add(context); + + Group confidential=GeoNetworkUtils.generateGroup(existingGroups, "Confidential_"+scopeName, "Confidential metadata group for "+scopeName, contactMail); + confidential=gnClient.createGroup(confidential); + existingGroups.add(confidential); + + // Giving access to shared group + log.debug("Giving access to shared group from external scopes.."); + for(User toUpdate:sharedGroupExternalUsers) + gnClient.editUser(toUpdate, Collections.singleton(shared.getId())); + + + log.debug("Creating users.."); + // CKAN -> sh,ctx + User ckan=GeoNetworkUtils.generateUser(existingUsers, passwordLength, "CKAN_"+scopeName); + ckan.setId(gnClient.createUsers(ckan, Arrays.asList(shared.getId(),context.getId())).getId()); + existingUsers.add(ckan); + + + // CTX-USR -> sh,ctx,siblings [sh], parents [sh,ctx] + User ctx=GeoNetworkUtils.generateUser(existingUsers, passwordLength, "Ctx_"+scopeName); + ArrayList ctxUserAccessibleGroups=new ArrayList<>(); + ctxUserAccessibleGroups.addAll(externalGroupsToAccess); + ctxUserAccessibleGroups.add(shared.getId()); + ctxUserAccessibleGroups.add(context.getId()); + ctx.setId(gnClient.createUsers(ctx, ctxUserAccessibleGroups).getId()); + existingUsers.add(ctx); + + // CTX-MANAGER -> sh,ctx,conf siblings [sh], parents [sh,ctx] + User manager=GeoNetworkUtils.generateUser(existingUsers, passwordLength, "Mng_"+scopeName); + ctxUserAccessibleGroups.add(confidential.getId()); + manager.setId(gnClient.createUsers(manager, ctxUserAccessibleGroups).getId()); + existingUsers.add(manager); + + // Setting information in Service Endpoint + log.debug("Inserting configuration in Service Endpoint"); + + String generatedSuffix=generateSuffix(suffixes); + + ArrayList toUpdateProperties=new ArrayList<>(); + toUpdateProperties.add( new Property().nameAndValue(assignedScopePrefix+generatedSuffix, scopeName)); + toUpdateProperties.add( new Property().nameAndValue(scopeUserPrefix+generatedSuffix, ctx.getUsername())); + toUpdateProperties.add( new Property().nameAndValue(scopePasswordPrefix+generatedSuffix, ISUtils.encryptString(ctx.getPassword())).encrypted(true)); + toUpdateProperties.add( new Property().nameAndValue(ckanUserPrefix+generatedSuffix, ckan.getUsername())); + toUpdateProperties.add( new Property().nameAndValue(ckanPasswordPrefix+generatedSuffix, ISUtils.encryptString(ckan.getPassword())).encrypted(true)); + toUpdateProperties.add( new Property().nameAndValue(managerUserPrefix+generatedSuffix, manager.getUsername())); + toUpdateProperties.add( new Property().nameAndValue(managerPasswordPrefix+generatedSuffix, ISUtils.encryptString(manager.getPassword())).encrypted(true)); + toUpdateProperties.add( new Property().nameAndValue(sharedGroupPrefix+generatedSuffix, shared.getId()+"")); + toUpdateProperties.add( new Property().nameAndValue(defaultGroupPrefix+generatedSuffix, shared.getId()+"")); + toUpdateProperties.add( new Property().nameAndValue(confidentialGroupPrefix+generatedSuffix, confidential.getId()+"")); + toUpdateProperties.add( new Property().nameAndValue(contextGroupPrefix+generatedSuffix, context.getId()+"")); + + + + String suffixesList=(suffixes!=null&&!suffixes.trim().isEmpty()&&suffixes!=",")?suffixes+","+generatedSuffix:generatedSuffix; + toUpdateProperties.add(new Property().nameAndValue(suffixesProperty, suffixesList)); + accessPoint.properties().addAll(toUpdateProperties); + throw new OutdatedServiceEndpointException("Created scope configuration for "+scopeName); + } + + + private String getSuffixByScope(String scopeName) { + log.debug("looking for scope {} suffix. Available suffixes are : {} ",scopeName,suffixes); + if(suffixes!=null) + for(String suff:suffixes.split(",")) + if(suff!=null&&!suff.isEmpty()) { + String propertyValue=getSEProperty(assignedScopePrefix+suff, false); + if(propertyValue!=null&&propertyValue.equals(scopeName)) return suff; + } + return null; + } + + + private static String generateSuffix(String existingSuffixes){ + log.debug("Generating suffix, existing are : "+existingSuffixes); + String[] suffixArray=existingSuffixes==null?new String[0]:existingSuffixes.split(","); + int maxIndex=0; + for(String suff:suffixArray){ + try{ + int actual=Integer.parseInt(suff); + if(actual>maxIndex) maxIndex=actual; + }catch(Throwable t){ + + } + } + String generated=(maxIndex+1)+""; + log.debug("Generated suffix is : "+generated); + return generated; + } + + + private HashSet getUserNamesByScope(String scope, boolean getContext, boolean getManager, boolean getCKAN){ + HashSet toReturn=new HashSet(); + String scopeName=ScopeUtils.getScopeName(scope); + String scopeSuffix=getSuffixByScope(scopeName); + if(scopeSuffix!=null) { // context might be not configured + if(getContext)toReturn.add(getSEProperty(scopeUserPrefix+scopeSuffix, true)); + if(getManager) { + String scopeManagerUserName=getSEProperty(managerUserPrefix+scopeSuffix, false); + if(scopeManagerUserName!=null) toReturn.add(scopeManagerUserName); + } + if(getCKAN) toReturn.add(getSEProperty(ckanUserPrefix+scopeSuffix, true)); + } + return toReturn; + } + + private HashSet getGroupIDSByScope(String scope, boolean getShared,boolean getContext,boolean getConfidential){ + HashSet toReturn=new HashSet(); + String scopeName=ScopeUtils.getScopeName(scope); + String scopeSuffix=getSuffixByScope(scopeName); + if(scopeSuffix!=null) { + if(getShared)toReturn.add(Integer.parseInt(getSEProperty(sharedGroupPrefix+scopeSuffix,true))); + if(getContext) toReturn.add(Integer.parseInt(getSEProperty(contextGroupPrefix+scopeSuffix, true))); + if(getConfidential) { + String confidentialGroupName=getSEProperty(confidentialGroupPrefix+scopeSuffix,true); + if(confidentialGroupName!=null) toReturn.add(Integer.parseInt(confidentialGroupName)); + } + } + return toReturn; + } + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoServerCluster.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoServerCluster.java new file mode 100644 index 0000000..57ad6dc --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoServerCluster.java @@ -0,0 +1,55 @@ +package org.gcube.spatial.data.sdi.engine.impl.cluster; + +import java.util.ArrayList; +import java.util.Comparator; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceInteractionException; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.service.GeoServerDescriptor; + +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class GeoServerCluster extends AbstractCluster{ + + private static final Comparator comparator=new Comparator() { + @Override + public int compare(GeoServerController o1, GeoServerController o2) { + return o1.getHostedLayersCount().compareTo(o2.getHostedLayersCount()); + } + }; + + + public GeoServerCluster(long objectsTTL, ISModule retriever, String cacheName) { + super(objectsTTL, retriever, cacheName); + // TODO Auto-generated constructor stub + } + + @Override + protected Comparator getComparator() { + return comparator; + } + + + @Override + protected GeoServerController translate(ServiceEndpoint e) throws InvalidServiceEndpointException { + return new GeoServerController(e); + } + + @Override + protected ArrayList getLiveControllerCollection() throws ConfigurationNotFoundException { + ArrayList toReturn= super.getLiveControllerCollection(); + for(GeoServerController controller:toReturn) + try{ + controller.configure(); + }catch(ServiceInteractionException e) { + log.warn("Unexpected exception while configuring GeoServer SE [ID : "+controller.getServiceEndpoint().id()+"]",e); + } + return toReturn; + + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoServerController.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoServerController.java new file mode 100644 index 0000000..9472730 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoServerController.java @@ -0,0 +1,244 @@ +package org.gcube.spatial.data.sdi.engine.impl.cluster; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.Property; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.faults.OutdatedServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.is.ISUtils; +import org.gcube.spatial.data.sdi.model.credentials.AccessType; +import org.gcube.spatial.data.sdi.model.credentials.Credentials; +import org.gcube.spatial.data.sdi.model.service.GeoServerDescriptor; + +import it.geosolutions.geoserver.rest.GeoServerRESTManager; +import it.geosolutions.geoserver.rest.GeoServerRESTPublisher; +import it.geosolutions.geoserver.rest.GeoServerRESTReader; +import it.geosolutions.geoserver.rest.manager.GeoServerRESTStoreManager; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GeoServerController extends GeoServiceController{ + + + + //CACHED INFO + private HashMap> dataStores=null; + private HashSet workspaces=null; + private HashSet styles; + private Long hostedLayerCount=0l; + + + public GeoServerController(ServiceEndpoint serviceEndpoint) throws InvalidServiceEndpointException { + super(serviceEndpoint); + } + + @Override + public GeoServerDescriptor getLiveDescriptor() { + GeoServerDescriptor toReturn=new GeoServerDescriptor(); + toReturn.setBaseEndpoint(baseURL); + toReturn.setVersion(version); + + String scopeName=ScopeUtils.getCurrentScopeName(); + + Map pointProperties=accessPoint.propertyMap(); + for(AccessType toLookForType:AccessType.values()) { + String userNameProperty=toLookForType+"_u_"+scopeName; + String passwordProperty=toLookForType+"_u_"+scopeName; + if(pointProperties.containsKey(userNameProperty)) { + String user=pointProperties.get(userNameProperty).value(); + String password=ISUtils.decryptString(pointProperties.get(passwordProperty).value()); + toReturn.getAccessibleCredentials().add(new Credentials(user,password,toLookForType)); + } + } + + toReturn.getAccessibleCredentials().add(adminAccount); + + //Getting scope data spaces + String confidentialProperty="confidential_"+scopeName; + if(pointProperties.containsKey(confidentialProperty)) + toReturn.setConfidentialWorkspace(pointProperties.get(confidentialProperty).value()); + String contextProperty="context_"+scopeName; + if(pointProperties.containsKey(contextProperty)) + toReturn.setContextVisibilityWorkspace(pointProperties.get(contextProperty).value()); + String sharedProperty="shared_"+scopeName; + if(pointProperties.containsKey(sharedProperty)) + toReturn.setSharedWorkspace(pointProperties.get(sharedProperty).value()); + String publicProperty="public_"+scopeName; + if(pointProperties.containsKey(publicProperty)) + toReturn.setPublicWorkspace(pointProperties.get(publicProperty).value()); + + toReturn.setHostedLayersCount(getHostedLayersCount()); + + return toReturn; + } + + @Override + protected AccessPoint getTheRightAccessPoint(ServiceEndpoint endpoint) { + for(AccessPoint declaredPoint:endpoint.profile().accessPoints().asCollection()) { + if(declaredPoint.name().equals(LocalConfiguration.getProperty(LocalConfiguration.GEOSERVER_SE_ENDPOINT_NAME))) { + return declaredPoint; + } + } + return null; + } + + + + + // Controller logic + + + @Override + protected void initServiceEndpoint() throws OutdatedServiceEndpointException { + // TODO Auto-generated method stub + } + + + + private long lastDatastoreUpdate=0l; + private long lastWorkspaceUpdate=0l; + private long lastStylesUpdate=0l; + private long lastLayerCountUpdate=0l; + + + public GeoServerRESTReader getReader() throws MalformedURLException{ + return getManager().getReader(); + } + + public GeoServerRESTStoreManager getDataStoreManager() throws IllegalArgumentException, MalformedURLException{ + return getManager().getStoreManager(); + } + + public GeoServerRESTPublisher getPublisher() throws IllegalArgumentException, MalformedURLException{ + return getManager().getPublisher(); + } + + protected GeoServerRESTManager getManager() throws IllegalArgumentException, MalformedURLException{ + return new GeoServerRESTManager(new URL(baseURL), adminAccount.getUsername(), adminAccount.getPassword()); + } + + + public synchronized Set getDatastores(String workspace){ + try { + if(dataStores==null || (System.currentTimeMillis()-lastDatastoreUpdate>LocalConfiguration.getTTL(LocalConfiguration.GEOSERVER_DATASTORE_TTL))){ + log.trace("Loading datastores for {} ",baseURL); + HashMap> toSet=new HashMap<>(); + for(String ws: getWorkspaces()){ + HashSet currentWsDatastores=new HashSet<>(getLiveDatastores(ws)); + log.debug("Found {} ds in {} ws ",currentWsDatastores.size(),ws); + toSet.put(ws, currentWsDatastores); + } + dataStores=toSet; + lastDatastoreUpdate=System.currentTimeMillis(); + } + }catch(Throwable t) { + log.warn("Unable to get Datastores for {} ",baseURL,t); + } + return dataStores.get(workspace); + } + + public synchronized Long getHostedLayersCount(){ + try{ + if(System.currentTimeMillis()-lastLayerCountUpdate>LocalConfiguration.getTTL(LocalConfiguration.GEOSERVER_HOSTED_LAYERS_TTL)){ + log.trace("Loading layer count for {} ",baseURL); + hostedLayerCount=getLiveHostedLayersCount(); + log.debug("Found {} layers ",hostedLayerCount); + lastLayerCountUpdate=System.currentTimeMillis(); + } + }catch(Throwable t){ + log.warn("Unable to get layer count for {} ",baseURL,t); + } + return hostedLayerCount; + } + + + public synchronized Set getStyles(){ + try { + if(styles==null||(System.currentTimeMillis()-lastStylesUpdate>LocalConfiguration.getTTL(LocalConfiguration.GEOSERVER_STYLES_TTL))){ + log.trace("Loading styles for {} ",baseURL); + styles=new HashSet<>(getLiveStyles()); + log.debug("Found {} styles ",styles.size()); + lastStylesUpdate=System.currentTimeMillis(); + } + }catch(Throwable t) { + log.warn("Unable to get Styles for {} ",baseURL,t); + } + return styles; + } + + + public synchronized Set getWorkspaces() { + try { + if(workspaces==null||(System.currentTimeMillis()-lastWorkspaceUpdate>LocalConfiguration.getTTL(LocalConfiguration.GEOSERVER_WORKSPACE_TTL))){ + log.trace("Loading workspaces for {} ",baseURL); + workspaces=new HashSet(getLiveWorkspaces()); + log.debug("Found {} workspaces",workspaces.size()); + lastWorkspaceUpdate=0l; + } + }catch(Throwable t) { + log.warn("Unable to get Workspaces for {} ",baseURL,t); + } + return workspaces; + } + + + public void invalidateWorkspacesCache(){ + lastWorkspaceUpdate=0l; + } + + public void invalidateDatastoresCache(){ + lastDatastoreUpdate=0l; + } + + public void invalidateStylesCache(){ + lastStylesUpdate=0l; + } + + public void invalidateHostedLayersCountCache(){ + lastLayerCountUpdate=0l; + } + + public void onChangedDataStores() { + invalidateDatastoresCache(); + } + public void onChangedLayers() { + invalidateHostedLayersCountCache(); + } + public void onChangedStyles() { + invalidateStylesCache(); + } + public void onChangedWorkspaces() { + invalidateWorkspacesCache(); + invalidateDatastoresCache(); + } + + + + public Set getLiveDatastores(String workspace) throws MalformedURLException { + return new HashSet(getReader().getDatastores(workspace).getNames()); + } + + + public Long getLiveHostedLayersCount() throws MalformedURLException { + return new Long(getReader().getLayers().size()); + } + + + public Set getLiveStyles() throws MalformedURLException { + return new HashSet(getReader().getStyles().getNames()); + } + + + public Set getLiveWorkspaces() throws MalformedURLException { + return new HashSet(getReader().getWorkspaceNames()); + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoServiceController.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoServiceController.java new file mode 100644 index 0000000..4b68949 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/GeoServiceController.java @@ -0,0 +1,100 @@ +package org.gcube.spatial.data.sdi.engine.impl.cluster; + +import java.util.Map; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.Profile; +import org.gcube.common.resources.gcore.ServiceEndpoint.Property; +import org.gcube.common.resources.gcore.common.Platform; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.faults.OutdatedServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceInteractionException; +import org.gcube.spatial.data.sdi.engine.impl.is.CachedObject; +import org.gcube.spatial.data.sdi.engine.impl.is.ISUtils; +import org.gcube.spatial.data.sdi.model.credentials.AccessType; +import org.gcube.spatial.data.sdi.model.credentials.Credentials; +import org.gcube.spatial.data.sdi.model.service.GeoServiceDescriptor; +import org.gcube.spatial.data.sdi.model.service.Version; + +import lombok.extern.slf4j.Slf4j; + + + +@Slf4j +public abstract class GeoServiceController { + + protected ServiceEndpoint serviceEndpoint; + protected AccessPoint accessPoint; + protected Map propertyMap; + protected String baseURL; + protected Credentials adminAccount; + protected Version version; + protected CachedObject cachedDescriptor=null; + + public synchronized T getDescriptor() { + if(cachedDescriptor==null||cachedDescriptor.isValid(500)) { + cachedDescriptor=new CachedObject(getLiveDescriptor()); + } + return cachedDescriptor.getTheObject(); + } + + protected abstract T getLiveDescriptor(); + + + protected abstract AccessPoint getTheRightAccessPoint(ServiceEndpoint endpoint); + + public GeoServiceController(ServiceEndpoint serviceEndpoint) throws InvalidServiceEndpointException{ + super(); + log.debug("Instantiating controller for SE {} ",serviceEndpoint); + setServiceEndpoint(serviceEndpoint); + } + + public void onUpdateServiceEndpoint() { + setServiceEndpoint(ISUtils.updateAndWait(serviceEndpoint)); + if(cachedDescriptor!=null)cachedDescriptor.invalidate(); + } + + protected void setServiceEndpoint(ServiceEndpoint toSet) { + this.serviceEndpoint = toSet; + + Profile profile=serviceEndpoint.profile(); + + accessPoint=getTheRightAccessPoint(serviceEndpoint); + if(accessPoint!=null) { + propertyMap=this.accessPoint.propertyMap(); + baseURL=accessPoint.address(); + adminAccount=new Credentials(accessPoint.username(),ISUtils.decryptString(accessPoint.password()),AccessType.ADMIN); + } + Platform platform=profile.platform(); + version=new Version(platform.version(),platform.minorVersion(),platform.revisionVersion()); + } + + + protected abstract void initServiceEndpoint() throws OutdatedServiceEndpointException, ServiceInteractionException; + + public void configure() throws ServiceInteractionException { + try { + initServiceEndpoint(); + }catch(OutdatedServiceEndpointException e) { + onUpdateServiceEndpoint(); + } + } + + + protected String getSEProperty(String property, boolean mandatory) throws InvalidServiceEndpointException{ + if(!propertyMap.containsKey(property)) + if(mandatory) + throw new InvalidServiceEndpointException("Expected property "+property+" was not found. in Resource ID "+getServiceEndpoint().id()); + else return null; + else { + Property prop=propertyMap.get(property); + if(prop.isEncrypted()) return ISUtils.decryptString(prop.value()); + else return prop.value(); + } + } + + public ServiceEndpoint getServiceEndpoint() { + return serviceEndpoint; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/ThreddsCluster.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/ThreddsCluster.java new file mode 100644 index 0000000..26f65ab --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/ThreddsCluster.java @@ -0,0 +1,28 @@ +package org.gcube.spatial.data.sdi.engine.impl.cluster; + +import java.util.Comparator; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.service.ThreddsDescriptor; + +public class ThreddsCluster extends AbstractCluster { + + + public ThreddsCluster(long objectsTTL, ISModule retriever, String cacheName) { + super(objectsTTL, retriever, cacheName); + // TODO Auto-generated constructor stub + } + + @Override + protected ThreddsController translate(ServiceEndpoint e) throws InvalidServiceEndpointException { + return new ThreddsController(e); + } + + @Override + protected Comparator getComparator() { + return null; + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/ThreddsController.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/ThreddsController.java new file mode 100644 index 0000000..7eec517 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/cluster/ThreddsController.java @@ -0,0 +1,136 @@ +package org.gcube.spatial.data.sdi.engine.impl.cluster; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; +import org.gcube.data.transfer.library.DataTransferClient; +import org.gcube.data.transfer.library.client.AuthorizationFilter; +import org.gcube.data.transfer.library.faults.DestinationNotSetException; +import org.gcube.data.transfer.library.faults.FailedTransferException; +import org.gcube.data.transfer.library.faults.InitializationException; +import org.gcube.data.transfer.library.faults.InvalidDestinationException; +import org.gcube.data.transfer.library.faults.InvalidSourceException; +import org.gcube.data.transfer.library.faults.SourceNotSetException; +import org.gcube.data.transfer.model.Destination; +import org.gcube.data.transfer.model.DestinationClashPolicy; +import org.gcube.data.transfer.model.PluginInvocation; +import org.gcube.data.transfer.model.TransferTicket; +import org.gcube.data.transfer.model.plugins.thredds.ThreddsCatalog; +import org.gcube.data.transfer.model.plugins.thredds.ThreddsInfo; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.NetUtils; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.faults.OutdatedServiceEndpointException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ThreddsOperationFault; +import org.gcube.spatial.data.sdi.engine.impl.is.ISUtils; +import org.gcube.spatial.data.sdi.engine.impl.metadata.GenericTemplates; +import org.gcube.spatial.data.sdi.model.CatalogDescriptor; +import org.gcube.spatial.data.sdi.model.service.ThreddsDescriptor; +import org.glassfish.jersey.client.ClientConfig; + +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class ThreddsController extends GeoServiceController { + + @Override + protected ThreddsDescriptor getLiveDescriptor() { + return new ThreddsDescriptor(version,baseURL,Collections.EMPTY_LIST); + } + + @Override + protected AccessPoint getTheRightAccessPoint(ServiceEndpoint endpoint) { + for(AccessPoint declaredPoint:endpoint.profile().accessPoints().asCollection()) { + if(declaredPoint.name().equals(LocalConfiguration.getProperty(LocalConfiguration.THREDDS_SE_REMOTE_MANAGEMENT_ACCESS))) { + return declaredPoint; + } + } + return null; + } + + public ThreddsController(ServiceEndpoint serviceEndpoint) throws InvalidServiceEndpointException { + super(serviceEndpoint); + } + + @Override + protected void initServiceEndpoint() throws OutdatedServiceEndpointException { + // TODO Auto-generated method stub + + } + + + public ThreddsInfo getThreddsInfo() { + String infoPath=getThreddsInfoPath(); + log.info("Loading thredds info from {} ",infoPath); + WebTarget target=getWebClient().target(infoPath); + return target.request(MediaType.APPLICATION_JSON).get(ThreddsInfo.class); + } + + + private void reloadCatalog() throws IOException { + AccessPoint ap=getTheRightAccessPoint(serviceEndpoint); + NetUtils.makeAuthorizedCall(ap.address(), ap.username(), ISUtils.decryptString(ap.password())); + + } + + private String getHostName() { + return getServiceEndpoint().profile().runtime().hostedOn(); + } + + private String getThreddsInfoPath() { + return "https://"+getHostName()+"/data-transfer-service/gcube/service/Capabilities/pluginInfo/REGISTER_CATALOG"; + } + + private Client getWebClient() { + + return ClientBuilder.newClient(new ClientConfig().register(AuthorizationFilter.class)); + } + + public ThreddsCatalog publishCatalog(File catalogFile, String reference) throws ThreddsOperationFault { + + log.trace("Registering Thredds catalog with reference {} ",reference); + try { + AccessPoint ap=getTheRightAccessPoint(getServiceEndpoint()); + + log.debug("AP address is {} ",ap.address()); + + DataTransferClient client=DataTransferClient.getInstanceByEndpoint(ap.address()); + + Destination dest=new Destination(); + dest.setPersistenceId("thredds"); + dest.setDestinationFileName(reference.replace(" ", "_")+".xml"); + dest.setOnExistingFileName(DestinationClashPolicy.REWRITE); + + PluginInvocation invocation=new PluginInvocation("REGISTER_CATALOG"); + invocation.setParameters(Collections.singletonMap("CATALOG_REFERENCE", reference)); + + log.debug("Sending catalog file to Thredds for registration"); + + client.localFile(catalogFile, dest,invocation); + + log.debug("Catalog registered, calling reload.. "); + + reloadCatalog(); + ThreddsInfo info=getThreddsInfo(); + log.debug("returned ThreddsInfo is {} ",info); + return info.getById(reference); + + } catch (InvalidSourceException | SourceNotSetException | FailedTransferException | InitializationException + | InvalidDestinationException | DestinationNotSetException e) { + throw new ThreddsOperationFault("Unable to register catalog "+reference, e); + }catch(Exception e) { + throw new ThreddsOperationFault("Unable to reload catalog "+reference,e); + } + + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/GeoNetworkManagerFactory.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/GeoNetworkManagerFactory.java new file mode 100644 index 0000000..17f37cf --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/GeoNetworkManagerFactory.java @@ -0,0 +1,27 @@ +package org.gcube.spatial.data.sdi.engine.impl.factories; + +import javax.inject.Inject; + +import org.gcube.spatial.data.sdi.engine.GeoNetworkManager; +import org.gcube.spatial.data.sdi.engine.RoleManager; +import org.gcube.spatial.data.sdi.engine.impl.GeoNetworkManagerImpl; +import org.glassfish.hk2.api.Factory; + +public class GeoNetworkManagerFactory implements Factory{ + + @Inject + private RoleManager manager; + + @Override + public void dispose(GeoNetworkManager instance) { + // TODO Auto-generated method stub + + } + + @Override + public GeoNetworkManager provide() { + + return new GeoNetworkManagerImpl(manager); + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/GeoServerManagerFactory.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/GeoServerManagerFactory.java new file mode 100644 index 0000000..c5c9faf --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/GeoServerManagerFactory.java @@ -0,0 +1,31 @@ +package org.gcube.spatial.data.sdi.engine.impl.factories; + +import org.gcube.spatial.data.sdi.engine.GISManager; +import org.gcube.spatial.data.sdi.engine.impl.GISManagerImpl; +import org.glassfish.hk2.api.Factory; + +import lombok.Synchronized; + +public class GeoServerManagerFactory implements Factory{ + + @Override + public void dispose(GISManager instance) { + // TODO Auto-generated method stub + + } + + @Override + public GISManager provide() { + return getInstance(); + } + + + private static GISManager instance=null; + + @Synchronized + private static GISManager getInstance() { + if(instance==null) + instance=new GISManagerImpl(); + return instance; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/MetadataTemplateManagerFactory.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/MetadataTemplateManagerFactory.java new file mode 100644 index 0000000..beddd8b --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/MetadataTemplateManagerFactory.java @@ -0,0 +1,36 @@ +package org.gcube.spatial.data.sdi.engine.impl.factories; + +import org.gcube.spatial.data.sdi.engine.TemplateManager; +import org.gcube.spatial.data.sdi.engine.impl.metadata.MetadataTemplateManagerImpl; +import org.glassfish.hk2.api.Factory; + +import lombok.Synchronized; + +public class MetadataTemplateManagerFactory implements Factory{ + @Override + public TemplateManager provide() { + return getInstance(); + } + + @Override + public void dispose(TemplateManager instance) { + // TODO Auto-generated method stub + + } + + + private static TemplateManager instance = null; + + @Synchronized + private static final TemplateManager getInstance() { + if(instance==null) { + instance=new MetadataTemplateManagerImpl(); + try { + ((MetadataTemplateManagerImpl)instance).defaultInit(); + }catch(Exception e) { + throw new RuntimeException("Unable to init temp ",e); + } + } + return instance; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/RoleManagerFactory.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/RoleManagerFactory.java new file mode 100644 index 0000000..c0ecb07 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/RoleManagerFactory.java @@ -0,0 +1,29 @@ +package org.gcube.spatial.data.sdi.engine.impl.factories; + +import org.gcube.spatial.data.sdi.engine.RoleManager; +import org.gcube.spatial.data.sdi.engine.impl.RoleManagerImpl; +import org.glassfish.hk2.api.Factory; + +import lombok.Synchronized; + +public class RoleManagerFactory implements Factory{ + + @Override + public void dispose(RoleManager instance) { + } + + + private static RoleManager instance; + + @Override + public RoleManager provide() { + return getInstance(); + } + + @Synchronized + private static RoleManager getInstance() { + if(instance==null) + instance=new RoleManagerImpl(); + return instance; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/SDIManagerFactory.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/SDIManagerFactory.java new file mode 100644 index 0000000..36552e6 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/SDIManagerFactory.java @@ -0,0 +1,44 @@ +package org.gcube.spatial.data.sdi.engine.impl.factories; + +import javax.inject.Inject; + +import org.gcube.spatial.data.sdi.engine.GISManager; +import org.gcube.spatial.data.sdi.engine.GeoNetworkManager; +import org.gcube.spatial.data.sdi.engine.SDIManager; +import org.gcube.spatial.data.sdi.engine.ThreddsManager; +import org.gcube.spatial.data.sdi.engine.impl.SDIManagerImpl; +import org.glassfish.hk2.api.Factory; + +import lombok.Synchronized; + +public class SDIManagerFactory implements Factory{ + + @Override + public void dispose(SDIManager instance) { + // TODO Auto-generated method stub + + } + @Override + public SDIManager provide() { + return getInstance(gnManager,gisManager,thManager); + } + + + private static SDIManager sdiManager=null; + + @Inject + private GeoNetworkManager gnManager; + @Inject + private GISManager gisManager; + @Inject + private ThreddsManager thManager; + + + + @Synchronized + private static SDIManager getInstance(GeoNetworkManager gnManager, GISManager gisManager,ThreddsManager thManager) { + if(sdiManager==null) + sdiManager=new SDIManagerImpl(gnManager,thManager,gisManager); + return sdiManager; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/TemporaryPersistenceFactory.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/TemporaryPersistenceFactory.java new file mode 100644 index 0000000..3bce8a9 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/TemporaryPersistenceFactory.java @@ -0,0 +1,37 @@ +package org.gcube.spatial.data.sdi.engine.impl.factories; + +import org.gcube.spatial.data.sdi.engine.TemporaryPersistence; +import org.gcube.spatial.data.sdi.engine.impl.TemporaryPersistenceImpl; +import org.glassfish.hk2.api.Factory; + +import lombok.Synchronized; + +public class TemporaryPersistenceFactory implements Factory{ + + + @Override + public void dispose(TemporaryPersistence arg0) { + arg0.shutdown(); + } + + @Override + public TemporaryPersistence provide() { + return getInstance(); + } + + + private static TemporaryPersistence temp=null; + + @Synchronized + private static TemporaryPersistence getInstance(){ + if(temp==null) { + temp=new TemporaryPersistenceImpl(); + try { + temp.init(); + }catch(Exception e) { + throw new RuntimeException("Unable to init temp ",e); + } + } + return temp; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/ThreddsManagerFactory.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/ThreddsManagerFactory.java new file mode 100644 index 0000000..ebb12fc --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/factories/ThreddsManagerFactory.java @@ -0,0 +1,37 @@ +package org.gcube.spatial.data.sdi.engine.impl.factories; + +import javax.inject.Inject; + +import org.gcube.spatial.data.sdi.engine.TemplateManager; +import org.gcube.spatial.data.sdi.engine.ThreddsManager; +import org.gcube.spatial.data.sdi.engine.impl.ThreddsManagerImpl; +import org.glassfish.hk2.api.Factory; + +import lombok.Synchronized; + +public class ThreddsManagerFactory implements Factory{ + + @Inject + private TemplateManager manager; + + + @Override + public ThreddsManager provide() { + return getInstance(manager); + } + + @Override + public void dispose(ThreddsManager instance) { + // TODO Auto-generated method stub + + } + + private static ThreddsManager instance=null; + + @Synchronized + private static ThreddsManager getInstance(TemplateManager manager) { + if(instance==null) + instance=new ThreddsManagerImpl(manager); + return instance; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ClientInitializationException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ClientInitializationException.java new file mode 100644 index 0000000..cfc7bb6 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ClientInitializationException.java @@ -0,0 +1,35 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults; + +public class ClientInitializationException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -4466379337497096292L; + + public ClientInitializationException() { + // TODO Auto-generated constructor stub + } + + public ClientInitializationException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public ClientInitializationException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public ClientInitializationException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public ClientInitializationException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ConfigurationNotFoundException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ConfigurationNotFoundException.java new file mode 100644 index 0000000..505706a --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ConfigurationNotFoundException.java @@ -0,0 +1,30 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults; + +public class ConfigurationNotFoundException extends Exception { + + public ConfigurationNotFoundException() { + // TODO Auto-generated constructor stub + } + + public ConfigurationNotFoundException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public ConfigurationNotFoundException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public ConfigurationNotFoundException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public ConfigurationNotFoundException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/GenericExceptionMapper.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/GenericExceptionMapper.java new file mode 100644 index 0000000..cb06547 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/GenericExceptionMapper.java @@ -0,0 +1,41 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +import org.gcube.spatial.data.sdi.model.faults.ErrorMessage; + + +public class GenericExceptionMapper implements ExceptionMapper { + + @Override + public Response toResponse(Throwable ex) { + + ErrorMessage errorMessage = new ErrorMessage(); + setHttpStatus(ex, errorMessage); + errorMessage.setCode(500); + errorMessage.setMessage(ex.getMessage()); + StringWriter errorStackTrace = new StringWriter(); + ex.printStackTrace(new PrintWriter(errorStackTrace)); + errorMessage.setDeveloperMessage(errorStackTrace.toString()); + errorMessage.setLink("www.d4science.org"); + + return Response.status(errorMessage.getStatus()) + .entity(errorMessage) + .type(MediaType.APPLICATION_JSON) + .build(); + } + + private void setHttpStatus(Throwable ex, ErrorMessage errorMessage) { + if(ex instanceof WebApplicationException ) { + errorMessage.setStatus(((WebApplicationException)ex).getResponse().getStatus()); + } else { + errorMessage.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); //defaults to internal server error 500 + } + } +} \ No newline at end of file diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/InvalidServiceDefinitionException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/InvalidServiceDefinitionException.java new file mode 100644 index 0000000..27fb26f --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/InvalidServiceDefinitionException.java @@ -0,0 +1,39 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults; + +public class InvalidServiceDefinitionException extends ServiceRegistrationException { + + /** + * + */ + private static final long serialVersionUID = -5251767289981417513L; + + public InvalidServiceDefinitionException() { + super(); + // TODO Auto-generated constructor stub + } + + public InvalidServiceDefinitionException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public InvalidServiceDefinitionException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public InvalidServiceDefinitionException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public InvalidServiceDefinitionException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/InvalidServiceEndpointException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/InvalidServiceEndpointException.java new file mode 100644 index 0000000..954a448 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/InvalidServiceEndpointException.java @@ -0,0 +1,38 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults; + +public class InvalidServiceEndpointException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = -3683038636163570578L; + + public InvalidServiceEndpointException() { + super(); + // TODO Auto-generated constructor stub + } + + public InvalidServiceEndpointException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public InvalidServiceEndpointException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public InvalidServiceEndpointException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public InvalidServiceEndpointException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/OutdatedServiceEndpointException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/OutdatedServiceEndpointException.java new file mode 100644 index 0000000..b3bb49e --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/OutdatedServiceEndpointException.java @@ -0,0 +1,38 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults; + +public class OutdatedServiceEndpointException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -1874537989302709012L; + + public OutdatedServiceEndpointException() { + super(); + // TODO Auto-generated constructor stub + } + + public OutdatedServiceEndpointException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public OutdatedServiceEndpointException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public OutdatedServiceEndpointException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public OutdatedServiceEndpointException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ServiceInteractionException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ServiceInteractionException.java new file mode 100644 index 0000000..788fbe9 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ServiceInteractionException.java @@ -0,0 +1,35 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults; + +public class ServiceInteractionException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 4708440073435829969L; + + public ServiceInteractionException() { + // TODO Auto-generated constructor stub + } + + public ServiceInteractionException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public ServiceInteractionException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public ServiceInteractionException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public ServiceInteractionException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ServiceRegistrationException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ServiceRegistrationException.java new file mode 100644 index 0000000..d61bfd3 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ServiceRegistrationException.java @@ -0,0 +1,38 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults; + +public class ServiceRegistrationException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -1570185699121566715L; + + public ServiceRegistrationException() { + super(); + // TODO Auto-generated constructor stub + } + + public ServiceRegistrationException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public ServiceRegistrationException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public ServiceRegistrationException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public ServiceRegistrationException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ThreddsOperationFault.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ThreddsOperationFault.java new file mode 100644 index 0000000..6d19096 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/ThreddsOperationFault.java @@ -0,0 +1,35 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults; + +public class ThreddsOperationFault extends ServiceInteractionException { + + /** + * + */ + private static final long serialVersionUID = -4389581996150834969L; + + public ThreddsOperationFault() { + // TODO Auto-generated constructor stub + } + + public ThreddsOperationFault(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public ThreddsOperationFault(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public ThreddsOperationFault(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public ThreddsOperationFault(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/gn/MetadataException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/gn/MetadataException.java new file mode 100644 index 0000000..219696a --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/gn/MetadataException.java @@ -0,0 +1,37 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults.gn; + +public class MetadataException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -234185402179551404L; + + public MetadataException() { + super(); + // TODO Auto-generated constructor stub + } + + public MetadataException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public MetadataException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public MetadataException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public MetadataException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/gn/MetadataNotFoundException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/gn/MetadataNotFoundException.java new file mode 100644 index 0000000..b3ba6e1 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/faults/gn/MetadataNotFoundException.java @@ -0,0 +1,38 @@ +package org.gcube.spatial.data.sdi.engine.impl.faults.gn; + +public class MetadataNotFoundException extends MetadataException { + + /** + * + */ + private static final long serialVersionUID = 5964532576083669460L; + + public MetadataNotFoundException() { + super(); + // TODO Auto-generated constructor stub + } + + public MetadataNotFoundException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public MetadataNotFoundException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public MetadataNotFoundException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public MetadataNotFoundException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GN26Extension.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GN26Extension.java new file mode 100644 index 0000000..b0e03a6 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GN26Extension.java @@ -0,0 +1,16 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.extension; + +import it.geosolutions.geonetwork.GN26Client; + +public class GN26Extension extends GN26Client { + + public GN26Extension(String serviceURL) { + super(serviceURL); + } + + public GN26Extension(String serviceURL, String username, String password) { + super(serviceURL, username, password); + super.connection=new HttpUtilsExtensions(username, password); + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GN3Extension.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GN3Extension.java new file mode 100644 index 0000000..3886dbb --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GN3Extension.java @@ -0,0 +1,17 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.extension; + +import it.geosolutions.geonetwork.GN3Client; + +public class GN3Extension extends GN3Client { + + public GN3Extension(String serviceURL) { + super(serviceURL); + // TODO Auto-generated constructor stub + } + + public GN3Extension(String serviceURL, String username, String password) { + super(serviceURL, username, password); + super.connection=new HttpUtilsExtensions(username, password); + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GNClientExtension.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GNClientExtension.java new file mode 100644 index 0000000..f4859cc --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GNClientExtension.java @@ -0,0 +1,177 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.extension; + +import java.io.File; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.gcube.spatial.data.sdi.engine.impl.gn.utils.GroupUtils; +import org.gcube.spatial.data.sdi.engine.impl.gn.utils.UserUtils; +import org.gcube.spatial.data.sdi.model.gn.Group; +import org.gcube.spatial.data.sdi.model.gn.User; +import org.gcube.spatial.data.sdi.model.gn.User.Profile; +import org.jdom.Element; + +import it.geosolutions.geonetwork.GNClient; +import it.geosolutions.geonetwork.exception.GNLibException; +import it.geosolutions.geonetwork.exception.GNServerException; +import it.geosolutions.geonetwork.op.gn3.GN3MetadataGetInfo.MetadataInfo; +import it.geosolutions.geonetwork.util.GNInsertConfiguration; +import it.geosolutions.geonetwork.util.GNPrivConfiguration; +import it.geosolutions.geonetwork.util.GNSearchRequest; +import it.geosolutions.geonetwork.util.GNSearchResponse; +import it.geosolutions.geonetwork.util.HTTPUtils; + +public class GNClientExtension implements GNClient { + + private GNClient client; + + private ServerAccess access; + + public GNClientExtension(ServerAccess access) { + this.access=access; + + if(access.getVersion().getMajor()==2) + client=new GN26Extension(access.getGnServiceURL(), access.getUser(), access.getPassword()); + else if(access.getVersion().getMajor()==3) + client = new GN3Extension(access.getGnServiceURL(), access.getUser(), access.getPassword()); + else throw new RuntimeException("INVALID SERVER ACCESS "+access); + + + } + + public void createGroup(String name, String description, String mail,Integer id)throws GNLibException, GNServerException { + GNMetadataAdminExtension.createGroup(getConnection(), access, name, description, mail, id); + } + + + public Set getGroups() throws GNLibException, GNServerException{ + String groupResponse=GNMetadataAdminExtension.getGroups(getConnection(), access); + if(access.getVersion().getMajor()==2) + return GroupUtils.parseGroupXMLResponse(groupResponse); + else return GroupUtils.parseUserJSONResponse(groupResponse); + } + + + + public Set getUsers() throws GNLibException, GNServerException{ + String userResponse=GNMetadataAdminExtension.getUsers(getConnection(), access); + if(access.getVersion().getMajor()==2) + return UserUtils.parseUserXMLResponse(userResponse); + else return UserUtils.parseUserJSONResponse(userResponse); + } + + + public void createUser(String name, String password, Profile profile, Collection groups) throws GNServerException, GNLibException{ + GNMetadataAdminExtension.createUser(getConnection(), access, name, password, profile, groups); + } + + public void editUser(User toAdd, Collection groups) throws GNServerException,GNLibException{ + Set alreadyAddedGroups=getGroupsByUser(toAdd.getId()); + alreadyAddedGroups.addAll(groups); + GNMetadataAdminExtension.editUser(getConnection(), access, toAdd, alreadyAddedGroups); + } + + public Set getGroupsByUser(Integer userId) throws GNLibException, GNServerException{ + return UserUtils.parseGroupsByUserResponse(GNMetadataAdminExtension.getUserGroupd(getConnection(), access, userId)); + } + + public void assignOwnership(List toTransferIds,Integer targetUserId,Integer targetGroupId) throws GNServerException, GNLibException{ + try{ + GNMetadataAdminExtension.selectMeta(getConnection(), access, toTransferIds); + GNMetadataAdminExtension.assignMassiveOwnership(getConnection(), access, targetUserId, targetGroupId); + }finally{ + GNMetadataAdminExtension.clearMetaSelection(getConnection(), access); + } + } + + public String getPossibleOwnershipTransfer(Integer userId) throws GNServerException, GNLibException{ + return GNMetadataAdminExtension.allowedOwnershipTransfer(getConnection(), access, userId); + } + public String getMetadataOwners() throws GNServerException, GNLibException{ + return GNMetadataAdminExtension.metadataOwners(getConnection(), access); + } + + public void transferOwnership(Integer sourceUserId,Integer sourceGroupId,Integer targetUserId,Integer targetGroupId) throws GNServerException, GNLibException{ + GNMetadataAdminExtension.transferOwnership(getConnection(), access, sourceUserId, sourceGroupId, targetUserId, targetGroupId); + } + + + + //***************************** OVERRIDES + + + @Override + public boolean ping() { + return client.ping(); + } + + @Override + public long insertMetadata(GNInsertConfiguration cfg, File metadataFile) throws GNLibException, GNServerException { + return client.insertMetadata(cfg, metadataFile); + } + + @Override + public long insertRequest(File requestFile) throws GNLibException, GNServerException { + return client.insertRequest(requestFile); + } + + @Override + public void setPrivileges(long metadataId, GNPrivConfiguration cfg) throws GNLibException, GNServerException { + client.setPrivileges(metadataId, cfg); + } + + @Override + public GNSearchResponse search(GNSearchRequest searchRequest) throws GNLibException, GNServerException { + return client.search(searchRequest); + } + + @Override + public GNSearchResponse search(File fileRequest) throws GNLibException, GNServerException { + return client.search(fileRequest); + } + + @Override + public Element get(Long id) throws GNLibException, GNServerException { + return client.get(id); + } + + @Override + public Element get(String uuid) throws GNLibException, GNServerException { + return client.get(uuid); + } + + @Override + public void deleteMetadata(long id) throws GNLibException, GNServerException { + client.deleteMetadata(id); + } + + @Override + public void updateMetadata(long id, File metadataFile) throws GNLibException, GNServerException { + client.updateMetadata(id, metadataFile); + } + + @Override + public void updateMetadata(long id, File metadataFile, String encoding) throws GNLibException, GNServerException { + client.updateMetadata(id, metadataFile,encoding); + } + + @Override + public MetadataInfo getInfo(Long id) throws GNLibException, GNServerException { + return client.getInfo(id); + } + + @Override + public MetadataInfo getInfo(String uuid) throws GNLibException, GNServerException { + return client.getInfo(uuid); + } + + @Override + public HTTPUtils getConnection() throws GNLibException { + return client.getConnection(); + } + + +} + + diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GNMetadataAdminExtension.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GNMetadataAdminExtension.java new file mode 100644 index 0000000..4e41fde --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GNMetadataAdminExtension.java @@ -0,0 +1,309 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.extension; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.util.Collection; +import java.util.List; + +import org.gcube.spatial.data.sdi.model.gn.User; +import org.gcube.spatial.data.sdi.model.gn.User.Profile; +import org.jdom.Element; +import org.jdom.output.Format; +import org.jdom.output.XMLOutputter; +import org.json.JSONArray; +import org.json.JSONObject; + +import it.geosolutions.geonetwork.exception.GNLibException; +import it.geosolutions.geonetwork.exception.GNServerException; +import it.geosolutions.geonetwork.util.HTTPUtils; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GNMetadataAdminExtension { + + private final static XMLOutputter outputter = new XMLOutputter(Format.getCompactFormat()); + + private final static String USER_3="/srv/api/0.1/users"; + private final static String GROUPS_3="/srv/api/0.1/groups"; + + + private final static String CREATE_GROUP_METHOD_2="/srv/en/group.update"; + + private final static String GROUP_LIST_METHOD="/srv/en/xml.group.list"; + private final static String USER_LIST_METHOD_2="/srv/en/xml.user.list"; + + private final static String CREATE_USER_METHOD="/srv/en/user.update"; + private final static String GET_GROUPS_BY_USER="/srv/en/xml.usergroups.list"; + private final static String METADATA_SELECT="/srv/en/metadata.select"; + private final static String ASSIGN_MASSIVE_OWNERSHIP="/srv/en/metadata.massive.newowner"; + private final static String AVAILABLE_OWNERSHIP="/srv/en/xml.ownership.groups"; + private final static String METADATA_OWNERS="/srv/en/xml.ownership.editors"; + private final static String TRANSFER_OWNSERSHIP="/srv/en/xml.ownership.transfer"; + + + + public static String allowedOwnershipTransfer(HTTPUtils connection, ServerAccess access, Integer userId) throws GNServerException, GNLibException{ + log.debug("Getting available ownership transfer for user "+userId); + Element request=new Element("request"); + request.addContent(new Element("id").setText(userId+"")); + return gnCall(connection,access,request,AVAILABLE_OWNERSHIP); + } + + public static String metadataOwners(HTTPUtils connection, ServerAccess access) throws GNServerException, GNLibException{ + log.debug("Getting metadata owners"); + Element request=new Element("request"); + return gnCall(connection,access,request,METADATA_OWNERS); + } + + public static String selectMeta (HTTPUtils connection, ServerAccess access, List toSelectIds) throws GNServerException, GNLibException{ + log.debug("Massive metadata selection.."); + Element request=buildSelectMetadata(toSelectIds); + return gnCall(connection,access,request,METADATA_SELECT); + } + + public static String clearMetaSelection(HTTPUtils connection, ServerAccess access) throws GNServerException, GNLibException{ + log.debug("Massive metadata selection.."); + Element request=buildClearMetaSelection(); + return gnCall(connection,access,request,METADATA_SELECT); + } + + public static String assignMassiveOwnership(HTTPUtils connection, ServerAccess access,Integer userId, Integer groupId) throws GNServerException, GNLibException{ + log.debug("Assign massive ownership to u:{},g:{} ",userId,groupId); + Element request=new Element("request"); + request.addContent(new Element("user").setText(userId+"")); + request.addContent(new Element("group").setText(groupId+"")); + return gnCall(connection,access,request,ASSIGN_MASSIVE_OWNERSHIP); + } + + + public static String transferOwnership(HTTPUtils connection, ServerAccess access,Integer sourceUserId, Integer sourceGroupId,Integer destUserId, Integer destGroupId) throws GNServerException, GNLibException{ + log.debug("Transfering ownership from u:{},g:{} to u:{},g:{}",sourceUserId,sourceGroupId,destUserId,destGroupId); + Element request=new Element("request"); + request.addContent(new Element("sourceUser").setText(sourceUserId+"")); + request.addContent(new Element("sourceGroup").setText(sourceGroupId+"")); + request.addContent(new Element("targetUser").setText(destUserId+"")); + request.addContent(new Element("targetGroup").setText(destGroupId+"")); + return gnCall(connection,access,request,TRANSFER_OWNSERSHIP); + } + + public static String editUser(HTTPUtils connection,ServerAccess access,User toAdd, Collection groups)throws GNLibException, GNServerException { + log.debug("Coupling user {} to groups {} ",toAdd,groups); + + Object request=null; + String method=null; + if(access.getVersion().getMajor()==2){ + Element requestEl = new Element("request"); + requestEl.addContent(new Element("operation").setText("editinfo")); + requestEl.addContent(new Element("id").setText(toAdd.getId()+"")); + requestEl.addContent(new Element("username").setText(toAdd.getUsername())); + requestEl.addContent(new Element("password").setText(toAdd.getPassword())); + requestEl.addContent(new Element("profile").setText(toAdd.getProfile().name())); + if(groups!=null){ + for(Integer groupId:groups)requestEl.addContent(new Element("groups").setText(groupId+"")); + } + request=requestEl; + method=CREATE_USER_METHOD; + }else{ + + try{ + JSONObject object=new JSONObject(); + object.put("username", toAdd.getUsername()); + object.put("password", toAdd.getPassword()); + object.put("profile",toAdd.getProfile().toString()); + object.put("enabled", true); + if(groups!=null){ + JSONArray array=new JSONArray(); + for(Integer groupId:groups) array.put(groupId+""); + object.put("groupsReviewer", array); + } + request= object; + method=USER_3+"/"+toAdd.getId(); + }catch(Exception e){ + throw new GNLibException("Unabel to create JSON request for group creation ", e); + } + // request=buildUpdateUserRequest(toAdd.getId(), toAdd.getUsername(), toAdd.getPassword(), toAdd.getProfile(), groups); + } + + return gnCall(connection,access,request,method); + } + + public static String getUserGroupd(HTTPUtils connection,ServerAccess access,Integer userId)throws GNLibException, GNServerException { + log.debug("Getting user groups.."); + return gnCall(connection,access,new Element("request").addContent(new Element("id").setText(userId+"")),GET_GROUPS_BY_USER); + } + + + public static String getUsers(HTTPUtils connection, ServerAccess access) throws GNServerException, GNLibException{ + log.debug("Requesting users.."); + + + if(access.getVersion().getMajor()==2){ + return gnCall(connection,access,new Element("request"),USER_LIST_METHOD_2); + }else { + String toReturn=gnCall(connection,access,null,USER_3); + return toReturn; + } + } + + public static String createUser(HTTPUtils connection, ServerAccess access, String name, String password, Profile profile, Collection groups ) throws GNServerException, GNLibException{ + + log.debug("Requesting users.."); + log.debug("Compiling admin request document"); + + Object userRequest=null; + String method=null; + + if(access.getVersion().getMajor()==2){ + Element request = new Element("request"); + request.addContent(new Element("operation").setText("newuser")); + request.addContent(new Element("username").setText(name)); + request.addContent(new Element("password").setText(password)); + request.addContent(new Element("profile").setText(profile.name())); + if(groups!=null){ + for(Integer groupId:groups)request.addContent(new Element("groups").setText(groupId+"")); + } + userRequest=request; + method=CREATE_USER_METHOD; + }else{ + try{ + JSONObject object=new JSONObject(); + object.put("username", name); + object.put("password", password); + object.put("profile",profile); + object.put("enabled", true); + if(groups!=null){ + JSONArray array=new JSONArray(); + for(Integer groupId:groups) array.put(groupId+""); + object.put("groupsReviewer", array); + } + userRequest= object; + method=USER_3; + }catch(Exception e){ + throw new GNLibException("Unabel to create JSON request for group creation ", e); + } + } + + + + return gnCall(connection,access,userRequest,method); + } + + + public static String createGroup(HTTPUtils connection, ServerAccess access, String groupName, String groupDescription, String groupMail, Integer groupId) throws GNLibException, GNServerException { + log.debug(String.format("Creating group [Name : %s, Description : %s, Mail : %s ",groupName,groupDescription,groupMail)); + + Object adminRequest=null; + String method=null; + if(access.getVersion().getMajor()==2){ + Element request = new Element("request"); + request.addContent(new Element("name").setText(groupName)); + request.addContent(new Element("description").setText(groupDescription)); + request.addContent(new Element("email").setText(groupMail)); + + adminRequest= request; + method=CREATE_GROUP_METHOD_2; + } else { + try{ + JSONObject object=new JSONObject(); + object.put("name", groupName); + object.put("description", groupDescription); + object.put("email", groupMail); + object.put("id",groupId); + adminRequest= object; + method=GROUPS_3; + }catch(Exception e){ + throw new GNLibException("Unabel to create JSON request for group creation ", e); + } + } + + + + + return gnCall(connection, access, adminRequest,method); + } + + + public static String getGroups(HTTPUtils connection,ServerAccess access) throws GNServerException, GNLibException{ + log.debug("Requesting groups.."); + Object request=null; + String method=null; + if(access.getVersion().getMajor()==2){ + request=new Element("request"); + method=GROUP_LIST_METHOD; + }else{ + method=GROUPS_3; + } + return gnCall(connection, access, request,method); + } + + + private static String gnCall(HTTPUtils connection,ServerAccess access, final Object gnRequest,String toInvokeMethod)throws GNServerException, GNLibException { + + String serviceURL = access.getGnServiceURL() + toInvokeMethod; + try{ + String result=gnRequest==null?gnGET(connection,serviceURL):gnPut(connection, serviceURL, gnRequest); + int httpStatus=connection.getLastHttpStatus(); + if(httpStatus<200 ||httpStatus>=300) + throw new GNServerException("Error executing call, received "+httpStatus+". Result is "+result); + return result; + }catch(MalformedURLException e){ + throw new GNServerException("Unable to send request ",e); + }catch(UnsupportedEncodingException e){ + throw new GNServerException("Unable to send request ", e); + }catch(GNLibException e){ + throw e; + } + } + + + + + + + + + + + private static Element buildSelectMetadata(List toSelectIds){ + log.debug("building selection request"); + Element request = new Element("request"); + if(toSelectIds!=null){ + for(Long id:toSelectIds) request.addContent(new Element("id").setText(id.toString())); + request.addContent(new Element("selected").setText("add")); + }else request.addContent(new Element("selected").setText("add-all")); + return request; + } + + private static Element buildClearMetaSelection(){ + log.debug("building selection request"); + Element request = new Element("request"); + request.addContent(new Element("selected").setText("remove-all")); + return request; + } + + private static String gnPut(HTTPUtils connection, String serviceURL, final Object gnRequest) throws UnsupportedEncodingException, GNLibException, GNServerException { + + if(gnRequest instanceof Element){ + + String s = outputter.outputString((Element)gnRequest); + + connection.setIgnoreResponseContentOnSuccess(false); + String res = connection.postXml(serviceURL, s); + + return res; + } else if (gnRequest instanceof JSONObject){ + String s=((JSONObject) gnRequest).toString(); + connection.setIgnoreResponseContentOnSuccess(false); + return ((HttpUtilsExtensions)connection).putJSON(serviceURL, s); + } else throw new GNLibException("Unable to manage request element "+gnRequest); + } + + + private static String gnGET(HTTPUtils connection, String serviceURL) throws MalformedURLException, GNServerException { + + connection.setIgnoreResponseContentOnSuccess(false); + String res = ((HttpUtilsExtensions)connection).getJSON(serviceURL); + + return res; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GeoNetworkClient.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GeoNetworkClient.java new file mode 100644 index 0000000..8a4d4c1 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GeoNetworkClient.java @@ -0,0 +1,179 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.extension; + +import java.io.File; +import java.util.Collection; +import java.util.EnumSet; +import java.util.Set; + +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceInteractionException; +import org.gcube.spatial.data.sdi.engine.impl.gn.utils.GroupUtils; +import org.gcube.spatial.data.sdi.engine.impl.gn.utils.UserUtils; +import org.gcube.spatial.data.sdi.model.gn.Group; +import org.gcube.spatial.data.sdi.model.gn.User; +import org.gcube.spatial.data.sdi.model.service.GeoNetworkDescriptor; +import org.gcube.spatial.data.sdi.model.service.Version; + +import it.geosolutions.geonetwork.exception.GNLibException; +import it.geosolutions.geonetwork.exception.GNServerException; +import it.geosolutions.geonetwork.util.GNInsertConfiguration; +import it.geosolutions.geonetwork.util.GNPriv; +import it.geosolutions.geonetwork.util.GNPrivConfiguration; +import it.geosolutions.geonetwork.util.GNSearchRequest; +import it.geosolutions.geonetwork.util.GNSearchResponse; +import lombok.extern.slf4j.Slf4j; + +@Slf4j + +public class GeoNetworkClient { + + private ServerAccess access; + private GNClientExtension theClient=null; + private GeoNetworkDescriptor descriptor=null; + + + public GeoNetworkClient(String baseURL, Version version, String password, String user, GeoNetworkDescriptor descriptor) { + this(baseURL,version,password,user); + this.descriptor=descriptor; + } + public GeoNetworkClient(String baseURL, Version version, String password, String user) { + super(); + this.access=new ServerAccess(baseURL,version,password,user); + theClient=new GNClientExtension(access); + } + + //************************************** GROUPS AND USERS + + + public Group createGroup(Group group)throws ServiceInteractionException{ + try { + theClient.createGroup(group.getName(), group.getDescription(), group.getMail(),group.getId()); + long submitTime=System.currentTimeMillis(); + + long timeout=LocalConfiguration.getTTL(LocalConfiguration.GEONETWORK_UPDATE_TIMEOUT); + long wait=LocalConfiguration.getTTL(LocalConfiguration.GEONETWORK_UPDATE_WAIT); + + log.debug("Waiting for created group to be available, timeout is {} ",timeout); + //wait for update to be available + Group created=null; + do{ + try{Thread.sleep(wait);}catch(InterruptedException e){} + created=GroupUtils.getByName(theClient.getGroups(), group.getName()); + }while(created==null && (System.currentTimeMillis()-submitTime>=timeout)); + + if(created==null) { + log.error("GN Update timeout {}ms reached. Group {} not created.",timeout,group); + throw new ServiceInteractionException("Reached timeout while creating group "+group.getName()); + } + return created; + }catch(ServiceInteractionException e) { + throw e; + }catch(Throwable t) { + throw new ServiceInteractionException("Unable to create group. ",t); + } + } + + public Set getGroups() throws ServiceInteractionException { + try { + return theClient.getGroups(); + } catch (Exception e) { + throw new ServiceInteractionException("Unable to get Groups from "+access,e); + } + } + + + public Set getUsers() throws ServiceInteractionException{ + try { + return theClient.getUsers(); + } catch (Exception e) { + throw new ServiceInteractionException("Unable to get Users from "+access,e); + } + } + + + public User createUsers(User user, Collection groups) throws ServiceInteractionException { + try{ + theClient.createUser(user.getUsername(), user.getPassword(), user.getProfile(), groups); + + long submitTime=System.currentTimeMillis(); + + long timeout=LocalConfiguration.getTTL(LocalConfiguration.GEONETWORK_UPDATE_TIMEOUT); + long wait=LocalConfiguration.getTTL(LocalConfiguration.GEONETWORK_UPDATE_WAIT); + log.debug("Waiting for created group to be available, timeout is {} ",timeout); + //wait for update to be available + User created=null; + do{ + try{Thread.sleep(wait);}catch(InterruptedException e){} + created=UserUtils.getByName(theClient.getUsers(), user.getUsername()); + }while(created==null && (System.currentTimeMillis()-submitTime>=timeout)); + if(created==null) { + log.error("GN Update timeout {}ms reached. User {} not created.",timeout,user.getUsername()); + throw new ServiceInteractionException("Reached timeout while creating user "+user.getUsername()); + } + return created; + }catch(ServiceInteractionException e) { + throw e; + }catch(Throwable t) { + throw new ServiceInteractionException("Unable to create User. ",t); + } + + } + + public void editUser(User toEdit, Collection toAddGroups) throws ServiceInteractionException{ + try{ + Set alreadyAddedGroups=getGroupsByUser(toEdit.getId()); + alreadyAddedGroups.addAll(toAddGroups); + GNMetadataAdminExtension.editUser(theClient.getConnection(), access, toEdit, alreadyAddedGroups); + }catch(Throwable t) { + throw new ServiceInteractionException("Unable to create User. ",t); + } + } + public Set getGroupsByUser(Integer userId) throws ServiceInteractionException{ + try{ + return UserUtils.parseGroupsByUserResponse(GNMetadataAdminExtension.getUserGroupd(theClient.getConnection(), access, userId)); + }catch(Throwable t) { + throw new ServiceInteractionException(t); + } + } + + + //******************************* METADATA INSERTION + + + public long insertMetadata(String category, String styleSheet,boolean validate, int group, boolean makePublic, File metadataFile) throws GNLibException, GNServerException { + GNInsertConfiguration configuration=new GNInsertConfiguration(); + configuration.setCategory(category); + configuration.setStyleSheet(styleSheet); + configuration.setValidate(validate); + configuration.setGroup(group+""); + log.debug("Inserting with {} ",configuration); + long toReturnId=theClient.insertMetadata(configuration, metadataFile); + GNPrivConfiguration privileges=(makePublic?getPrivileges(group, + Integer.parseInt(descriptor.getPublicGroup())):getPrivileges(group)); + + log.debug("Setting privileges {} on {} ",privileges,toReturnId); + + theClient.setPrivileges(toReturnId, privileges); + return toReturnId; + } + + private static final GNPrivConfiguration getPrivileges(Integer...groups ) { + GNPrivConfiguration toReturn=new GNPrivConfiguration(); + for(Integer group:groups) + toReturn.addPrivileges(group, EnumSet.of(GNPriv.DOWNLOAD,GNPriv.DYNAMIC,GNPriv.EDITING,GNPriv.FEATURED,GNPriv.NOTIFY,GNPriv.VIEW)); + return toReturn; + } + + + public void updateMeta(long toUpdateMetaId,File metadataFile) throws GNLibException, GNServerException{ + log.debug("Updating metadata by ID "+toUpdateMetaId); + theClient.updateMetadata(toUpdateMetaId, metadataFile); + } + + + //********************************* SEARCH + public GNSearchResponse query(GNSearchRequest request) throws GNLibException, GNServerException{ + return theClient.search(request); + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GeoNetworkUtils.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GeoNetworkUtils.java new file mode 100644 index 0000000..fd0570f --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/GeoNetworkUtils.java @@ -0,0 +1,89 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.extension; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.impl.faults.gn.MetadataNotFoundException; +import org.gcube.spatial.data.sdi.model.gn.Group; +import org.gcube.spatial.data.sdi.model.gn.User; +import org.gcube.spatial.data.sdi.model.gn.User.Profile; +import org.gcube.spatial.data.sdi.utils.StringUtils; + +import it.geosolutions.geonetwork.exception.GNLibException; +import it.geosolutions.geonetwork.exception.GNServerException; +import it.geosolutions.geonetwork.util.GNSearchRequest; +import it.geosolutions.geonetwork.util.GNSearchRequest.Config; +import it.geosolutions.geonetwork.util.GNSearchResponse; +import it.geosolutions.geonetwork.util.GNSearchResponse.GNMetadata; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GeoNetworkUtils { + + /** + * Adds a suffix to groupName if needed + * + * @param existing + * @param groupName + * @return + */ + public static Group generateGroup(Set existing, String groupName, String description, String contactMail){ + Set existingNames=new HashSet<>(); + int maxId=0; + for(Group g:existing){ + existingNames.add(g.getName()); + if(maxIdmaxLength) + return generateGroup(existing, toUseName.substring(0, maxLength-2), description, contactMail); + return new Group(toUseName, description, contactMail, maxId+1); + } + + + public static User generateUser(Set existing, Integer passwordLength, String username){ + Set existingNames=new HashSet<>(); + for(User g:existing)existingNames.add(g.getUsername()); + + String toUseUserName=clashSafeString(username,existingNames); + + return new User(0, // NB will be updated when creating it.. + toUseUserName, + StringUtils.generateRandomString(passwordLength),Profile.Reviewer); + } + + + public static String clashSafeString(String originalString,Set existingSet) { + String toReturn=originalString; + int suffix=1; + while(existingSet.contains(toReturn)) { + toReturn=originalString+"_"+suffix; + suffix++; + } + return toReturn; + } + + + + public static long getIDByUUID(GeoNetworkClient client, String uuid) throws MetadataNotFoundException, GNLibException, GNServerException { + log.debug("Looking for uuid : {} ",uuid); + + GNSearchRequest req=new GNSearchRequest(); + req.addParam(GNSearchRequest.Param.any,uuid); + req.addConfig(Config.similarity, "1"); + + GNSearchResponse resp=client.query(req); + + Iterator iterator=resp.iterator(); + log.debug("Got {} hits for UUID {}",resp.getCount(),uuid); + while(iterator.hasNext()){ + GNMetadata meta=iterator.next(); + if(meta.getUUID().equals(uuid)) return meta.getId(); + } + throw new MetadataNotFoundException("Unable to find metadata from uuid "+uuid); + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/HttpUtilsExtensions.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/HttpUtilsExtensions.java new file mode 100644 index 0000000..5a1ccb3 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/HttpUtilsExtensions.java @@ -0,0 +1,281 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.extension; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + +import org.apache.commons.httpclient.Credentials; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.auth.AuthScope; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.commons.httpclient.methods.RequestEntity; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.apache.commons.io.IOUtils; + +import it.geosolutions.geonetwork.exception.GNServerException; +import it.geosolutions.geonetwork.util.HTTPUtils; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HttpUtilsExtensions extends HTTPUtils { + + + private final static String JSON_CONTENT_TYPE="application/json"; + private final static String XML_CONTENT_TYPE="text/xml"; + + + + + + public HttpUtilsExtensions() { + super(); + // TODO Auto-generated constructor stub + } + + String username; + String pw; + private int lastHttpStatus=0; + + public HttpUtilsExtensions(String userName, String password) { + super(userName, password); + this.username=userName; + this.pw=password; + } + + + HttpClient client=new HttpClient(); + + + public String getJSON(String url) throws MalformedURLException, GNServerException { + + GetMethod httpMethod = null; + try { + setAuth(client, url, username, pw); + + // creating call + + httpMethod = new GetMethod(url); + + //only actual difference from superclass + httpMethod.setRequestHeader("Accept", JSON_CONTENT_TYPE); + + + client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); + lastHttpStatus = client.executeMethod(httpMethod); + if(lastHttpStatus == HttpStatus.SC_OK) { + InputStream is = httpMethod.getResponseBodyAsStream(); + String response = IOUtils.toString(is); + if(response.trim().length()==0) { // sometime gs rest fails + log.warn("ResponseBody is empty"); + return null; + } else { + return response; + } + } else { + log.info("("+lastHttpStatus+") " + HttpStatus.getStatusText(lastHttpStatus) + " -- " + url ); + throw new GNServerException("ERROR from calling "+url, lastHttpStatus); + } + } catch (ConnectException e) { + log.info("Couldn't connect to ["+url+"]"); + } catch (IOException e) { + log.info("Error talking to ["+url+"]", e); + } finally { + if(httpMethod != null) + httpMethod.releaseConnection(); + } + + return null; + } + + + public String putJSON(String url, String content) throws UnsupportedEncodingException, GNServerException{ + PutMethod httpMethod=null; + try { + setAuth(client, url, username, pw); + httpMethod=new PutMethod(url); + client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); + httpMethod.setRequestEntity(new StringRequestEntity(content,JSON_CONTENT_TYPE,"UTF-8")); + + + //only actual difference from superclass + httpMethod.setRequestHeader("Accept", JSON_CONTENT_TYPE); + + + lastHttpStatus = client.executeMethod(httpMethod); + + + + if((lastHttpStatus>=200)&&(lastHttpStatus<300)){ + //OK responses + log.debug("HTTP "+ httpMethod.getStatusText() + " <-- " + url); + InputStream responseStream=httpMethod.getResponseBodyAsStream(); + if(super.isIgnoreResponseContentOnSuccess()||responseStream==null) + return ""; + return IOUtils.toString(responseStream); + }else{ + //NOT OK responses + String badresponse = IOUtils.toString(httpMethod.getResponseBodyAsStream()); + String message = super.getGeoNetworkErrorMessage(badresponse); + + log.warn("Bad response: "+lastHttpStatus + + " " + httpMethod.getStatusText() + + " -- " + httpMethod.getName() + + " " +url + + " : " + + message + ); + + log.debug("GeoNetwork response:\n"+badresponse); + throw new GNServerException("ERROR from calling "+url+". Message is "+badresponse, lastHttpStatus); + } + + } catch (ConnectException e) { + log.info("Couldn't connect to ["+url+"]"); + return null; + } catch (IOException e) { + log.error("Error talking to " + url + " : " + e.getLocalizedMessage()); + return null; + } finally { + if(httpMethod != null) + httpMethod.releaseConnection(); + } + } + + + + + protected void setAuth(HttpClient client, String url, String username, String pw) throws MalformedURLException { + URL u = new URL(url); + if(username != null && pw != null) { + Credentials defaultcreds = new UsernamePasswordCredentials(username, pw); + client.getState().setCredentials(new AuthScope(u.getHost(), u.getPort()), defaultcreds); + client.getParams().setAuthenticationPreemptive(true); // if we have the credentials, force them! + } else { + log.trace("Not setting credentials to access to " + url); + } + } + + private void reset(){ + // resets stats in subclass + this.lastHttpStatus=0; + } + + private boolean isReset(){ + return lastHttpStatus==0; + } + + @Override + public int getLastHttpStatus() { + if(isReset()) + return super.getLastHttpStatus(); + else return this.lastHttpStatus; + } + + + // OVERRIDING superclass methods in order to discriminate on lastHttpStatus member + + @Override + public boolean delete(String arg0) { + reset(); + return super.delete(arg0); + } + + @Override + public boolean exists(String arg0) { + reset(); + return super.exists(arg0); + } + + @Override + public String get(String arg0) throws MalformedURLException { + reset(); + return super.get(arg0); + } + + @Override + public boolean httpPing(String arg0) { + reset(); + return super.httpPing(arg0); + } + + @Override + public String post(String arg0, String arg1, String arg2, String arg3) { + reset(); + return super.post(arg0, arg1, arg2, arg3); + } + + @Override + public String post(String url, File file, String contentType) { + reset(); + return super.post(url, file, contentType); + } + + @Override + public String post(String url, InputStream content, String contentType) { + reset(); + return super.post(url, content, contentType); + } + + @Override + public String post(String url, RequestEntity requestEntity) { + reset(); + return super.post(url, requestEntity); + } + + @Override + public String post(String url, String content, String contentType) { + reset(); + return super.post(url, content, contentType); + } + + @Override + public String postXml(String url, InputStream content) { + reset(); + return super.postXml(url, content); + } + + @Override + public String postXml(String url, String content) { + reset(); + return super.postXml(url, content); + } + + @Override + public String postXml(String url, String content, String encoding) { + reset(); + return super.postXml(url, content, encoding); + } + + @Override + public String put(String arg0, String arg1, String arg2) { + reset(); + return super.put(arg0, arg1, arg2); + } + + @Override + public String put(String url, File file, String contentType) { + reset(); + return super.put(url, file, contentType); + } + @Override + public String put(String url, RequestEntity requestEntity) { + reset(); + return super.put(url, requestEntity); + } + + @Override + public String putXml(String url, String content) { + reset(); + return super.putXml(url, content); + } + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/ServerAccess.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/ServerAccess.java new file mode 100644 index 0000000..9d432fc --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/extension/ServerAccess.java @@ -0,0 +1,34 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.extension; + +import org.gcube.spatial.data.sdi.model.service.Version; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class ServerAccess{ + + + private String gnServiceURL; + private Version version; + + private String password; + private String user; + + + public ServerAccess(String gnServiceURL, Version version) { + super(); + this.gnServiceURL = gnServiceURL; + this.version = version; + } + + + @Override + public String toString() { + return "ServerAccess [gnServiceURL=" + gnServiceURL + ", version=" + version + ", password=****" + ", user=" + user + "]"; + } + + + +} \ No newline at end of file diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/utils/GroupUtils.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/utils/GroupUtils.java new file mode 100644 index 0000000..29ab3a7 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/utils/GroupUtils.java @@ -0,0 +1,88 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.utils; + +import java.io.StringReader; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; + +import org.gcube.spatial.data.sdi.model.gn.Group; +import org.gcube.spatial.data.sdi.utils.StringUtils; +import org.jdom.Element; +import org.jdom.input.SAXBuilder; +import org.json.JSONArray; +import org.json.JSONObject; + +import it.geosolutions.geonetwork.exception.GNLibException; + +public class GroupUtils { + + private static XPath xpath = XPathFactory.newInstance().newXPath(); + + + public static Set parseGroupXMLResponse(String xml) throws GNLibException { + try{ + HashSet toReturn=new HashSet<>(); + SAXBuilder builder = new SAXBuilder(); + org.jdom.Element responseEl= builder.build(new StringReader(xml)).detachRootElement(); + for(Object recordObj:responseEl.getChildren("record")){ + org.jdom.Element record=(org.jdom.Element) recordObj; + Integer id=Integer.parseInt(record.getChild("id").getText()); + String name=record.getChild("name").getText(); + Element descElement=record.getChild("description"); + String description=descElement!=null?descElement.getText():""; + Element mailElement=record.getChild("email"); + String email=mailElement!=null?mailElement.getText():""; + toReturn.add(new Group(name,description,email,id)); + } + return toReturn; + }catch(Exception e){ + throw new GNLibException("Unable to parse response", e); + } + + } + + public static Set parseUserJSONResponse(String groupResponse) throws GNLibException { + try{ + HashSet toReturn=new HashSet<>(); + JSONArray array=new JSONArray(groupResponse); + for(int i=0;i existing, Integer nameLenght){ + Set existingNames=new HashSet<>(); + int maxId=0; + for(Group g:existing){ + existingNames.add(g.getName()); + if(maxId toLookInto,String toLookFor){ + for(Group g:toLookInto) + if(g.getName().equals(toLookFor)) return g; + return null; + } + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/utils/UserUtils.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/utils/UserUtils.java new file mode 100644 index 0000000..c15ba68 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/gn/utils/UserUtils.java @@ -0,0 +1,88 @@ +package org.gcube.spatial.data.sdi.engine.impl.gn.utils; + +import java.io.StringReader; +import java.util.HashSet; +import java.util.Set; + +import org.gcube.spatial.data.sdi.model.gn.User; +import org.gcube.spatial.data.sdi.model.gn.User.Profile; +import org.gcube.spatial.data.sdi.utils.StringUtils; +import org.jdom.input.SAXBuilder; +import org.json.JSONArray; +import org.json.JSONObject; + +import it.geosolutions.geonetwork.exception.GNLibException; + +public class UserUtils { + + + public static Set parseUserXMLResponse(String toParse) throws GNLibException{ + try{ + HashSet toReturn=new HashSet<>(); + SAXBuilder builder = new SAXBuilder(); + org.jdom.Element responseEl= builder.build(new StringReader(toParse)).detachRootElement(); + for(Object recordObj:responseEl.getChildren("record")){ + org.jdom.Element record=(org.jdom.Element) recordObj; + Integer id=Integer.parseInt(record.getChildText("id")); + String username=record.getChildText("username"); + String password=record.getChildText("password"); + Profile profile=Profile.valueOf(record.getChildText("profile")); + toReturn.add(new User(id,username, password, profile)); + } + return toReturn; + }catch(Exception e){ + throw new GNLibException("Unable to parse users XML response", e); + } + + } + + + public static Set parseUserJSONResponse(String toParse)throws GNLibException{ + try{ + HashSet toReturn=new HashSet<>(); + JSONArray array=new JSONArray(toParse); + for(int i=0;i existing, Integer nameLenght, Integer passwordLength){ + Set existingNames=new HashSet<>(); + for(User g:existing)existingNames.add(g.getUsername()); + return new User(0,StringUtils.generateNewRandom(existingNames, nameLenght),StringUtils.generateRandomString(passwordLength),Profile.RegisteredUser); + } + + + public static Set parseGroupsByUserResponse(String toParse) throws GNLibException{ + try{ + HashSet toReturn=new HashSet<>(); + SAXBuilder builder = new SAXBuilder(); + org.jdom.Element responseEl= builder.build(new StringReader(toParse)).detachRootElement(); + for(Object recordObj:responseEl.getChildren("group")){ + org.jdom.Element record=(org.jdom.Element) recordObj; + Integer id=Integer.parseInt(record.getChildText("id")); + toReturn.add(id); + } + return toReturn; + }catch(Exception e){ + throw new GNLibException("Unable to Groups By User XML response", e); + } + } + + + public static User getByName(Set toLookInto,String toLookFor){ + for(User g:toLookInto) + if(g.getUsername().equals(toLookFor)) return g; + return null; + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/AbstractISModule.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/AbstractISModule.java new file mode 100644 index 0000000..c639174 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/AbstractISModule.java @@ -0,0 +1,260 @@ +package org.gcube.spatial.data.sdi.engine.impl.is; + +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; +import org.gcube.common.resources.gcore.GCoreEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.Profile; +import org.gcube.common.resources.gcore.common.Platform; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceDefinitionException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceRegistrationException; +import org.gcube.spatial.data.sdi.model.health.Level; +import org.gcube.spatial.data.sdi.model.health.ServiceHealthReport; +import org.gcube.spatial.data.sdi.model.health.Status; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition; + +import lombok.Synchronized; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class AbstractISModule implements ISModule { + + protected abstract String getGCoreEndpointServiceClass(); + protected abstract String getGCoreEndpointServiceName(); + protected abstract String getServiceEndpointAccessPointName(); + protected abstract String getServiceEndpointCategory(); + protected abstract String getServiceEndpointPlatformName(); + + protected abstract String getManagedServiceType(); + + protected abstract boolean isSmartGearsMandatory(); + + @Override + public List getISInformation() throws ConfigurationNotFoundException { + log.trace("Getting current information from IS. Scope {} ",ScopeUtils.getCurrentScope()); + ArrayList toReturn=new ArrayList<>(); + log.debug("MANDATORY SG FOR {} is {} ",getManagedServiceType(),isSmartGearsMandatory()); + if(isSmartGearsMandatory()) { + List GCs=queryGcoreEndpoints(); + for(ServiceEndpoint ep: queryServiceEndpoints()) { + String host=ISUtils.getHost(ep); + log.debug("Checking if ServiceEndpoint at {} is SmartGears .. ",host); + try{ + if(ISUtils.getByHostnameInCollection(host, GCs)!=null) { + log.debug("Found GC. Service Endpoint {} seems valid. ",ep.profile().name()); + toReturn.add(ep); + } + }catch(UnknownHostException e) { + log.warn("Unexpected Exception while checking hostnames. Please check configuration.",e); + } + } + }else { + toReturn.addAll(queryServiceEndpoints()); + } + return toReturn; + } + + + @Override + public ServiceHealthReport getHealthReport() { + List checkStatuses=new ArrayList<>(); + try { + + log.trace("Checking {} heatlh under context {} ",getManagedServiceType(),ScopeUtils.getCurrentScope()); + //Check if existing + List gCoreEndpoints=queryGcoreEndpoints(); + List serviceEndpoints=queryServiceEndpoints(); + log.debug("Found {} GC Endpoints and {} SE Endpoints",gCoreEndpoints.size(),serviceEndpoints.size()); + + if(serviceEndpoints.isEmpty()) + if(gCoreEndpoints.isEmpty())checkStatuses.add(new Status("No "+getManagedServiceType()+" found in context "+ScopeUtils.getCurrentScope(),Level.ERROR)); + else checkStatuses.add(new Status("Unregistered "+getManagedServiceType()+" instances found. Check following messages",Level.ERROR)); + + //For each GC check for missing SE + for(GCoreEndpoint gc:gCoreEndpoints) { + String hostname= gc.profile().endpoints().iterator().next().uri().getHost(); + if(ISUtils.getByHostnameInCollection(hostname, serviceEndpoints)==null) { + String msg="Found unregistered "+getManagedServiceType()+" hosted on "+hostname; + log.debug(msg); + checkStatuses.add(new Status(msg,Level.WARNING)); + } + } + + + for(ServiceEndpoint se : serviceEndpoints) { + try { + //check if GC up & running + String hostname=se.profile().runtime().hostedOn(); + GCoreEndpoint found=ISUtils.getByHostnameInCollection(hostname, gCoreEndpoints); + + if(found==null) + checkStatuses.add(new Status("Service endpoint [name = "+se.profile().name()+", host = "+hostname+" ID = "+se.id()+"] found but no related GC is present.",Level.ERROR)); + else { + String status=found.profile().deploymentData().status(); + switch(status) { + case "unreachable" : + case "down" : checkStatuses.add(new Status("GCoreEndpoint [ID "+found.id()+"] for instance hosted on "+hostname+" has status : "+status,Level.ERROR)); + break; + default : + } + } + + + // perform specific checks + checkStatuses.addAll(performInstanceCheck(se)); + }catch(Throwable t) { + log.error("Unable to perform checks on SE "+se.id(), t); + checkStatuses.add(new Status("Internal error while checking "+getManagedServiceType()+" [SE ID : "+se.id()+"]."+t.getMessage(),Level.ERROR)); + } + } + + }catch(Throwable t) { + log.error("Unable to perform checks", t); + checkStatuses.add(new Status("Internal error while checking "+getManagedServiceType()+" Status.",Level.ERROR)); + } + return new ServiceHealthReport(checkStatuses); + } + + protected abstract List performInstanceCheck(ServiceEndpoint se); + + + protected List queryGcoreEndpoints(){ + String geClass=getGCoreEndpointServiceClass(); + String geName=getGCoreEndpointServiceName(); + return ISUtils.queryForGCoreEndpoint(geClass, geName); + } + + + protected List queryServiceEndpoints(){ + String seCategory=getServiceEndpointCategory(); + String sePlatform=getServiceEndpointPlatformName(); + return ISUtils.queryForServiceEndpoints(seCategory, sePlatform); + } + + + + @Override + public String importHostFromToken(String sourceToken, String host) throws ServiceRegistrationException { + + log.trace("Importing host {} from token {} ",host,sourceToken); + String callerScope=ScopeUtils.getCurrentScope(); + String callerToken=SecurityTokenProvider.instance.get(); + try { + //Checking if already present + List existingSEs=ISUtils.querySEByHostname(getServiceEndpointCategory(), getServiceEndpointPlatformName(), host); + if(existingSEs.size()>0) { + throw new ServiceRegistrationException("HOST "+host+" is already registered in current scope with ID : "+existingSEs.get(0).id()); + } + + // Getting from sourceToken.. + SecurityTokenProvider.instance.set(sourceToken); + log.debug("Source token {} is from scope {}.",sourceToken,ScopeUtils.getCurrentScope()); + List foundSEs=ISUtils.querySEByHostname(getServiceEndpointCategory(), getServiceEndpointPlatformName(), host); + if(foundSEs.size()>1) throw new ServiceRegistrationException("Too many ServiceEndpoints found with hostname "+host); + else if(foundSEs.isEmpty()) throw new ServiceRegistrationException("No ServiceEndpoints found with hostname "+host); + + ServiceEndpoint toImportSE= foundSEs.get(0); + try { + GCoreEndpoint toImportGC = ISUtils.getByHostnameInCollection(host, queryGcoreEndpoints()); + if(toImportGC==null) throw new ServiceRegistrationException("No GCoreEndpoint found for hostname "+host); + + log.debug("Registering resources to caller scope {} ",callerScope); + return ISUtils.addToScope(toImportSE, toImportGC,callerScope); + }catch(Exception e) { + throw new ServiceRegistrationException("Unable to register resources",e); + } + + + }finally { + if(!SecurityTokenProvider.instance.get().equals(callerToken)) + SecurityTokenProvider.instance.set(callerToken); + } + } + + @Override + @Synchronized + public String registerService(ServiceDefinition definition) throws ServiceRegistrationException { + log.info("Registering {} ",definition); + log.debug("Checking definition type.."); + checkDefinitionType(definition); + log.debug("Checking IS .."); + checkDefinition(definition); + log.debug("Performing type specific checks.."); + checkDefinitionForServiceType(definition); + log.debug("Preparing ServiceEndpoint.. "); + ServiceEndpoint ep=prepareEndpoint(definition); + log.debug("Publishing resource.."); + String id=ISUtils.registerService(ep); + + List registered=null; + long registrationTime=System.currentTimeMillis(); + long timeout=Long.parseLong(LocalConfiguration.getProperty(LocalConfiguration.IS_REGISTRATION_TIMEOUT)); + do{ + log.debug("Waiting for IS to update. Passed {} ms.",(System.currentTimeMillis()-registrationTime)); + try{Thread.sleep(500); + }catch(Exception e) {} + + registered=ISUtils.queryById(id); + }while(registered.isEmpty()&&((System.currentTimeMillis()-registrationTime)<=timeout)); + if(registered.isEmpty()) { + log.warn("Registered resource [ID :{}] was not found before Timeout of {} ms. Returning id. ",id,timeout); + return id; + }else return registered.get(0); + } + + + protected abstract void checkDefinitionForServiceType(ServiceDefinition definition) throws InvalidServiceDefinitionException; + protected abstract void checkDefinitionType(ServiceDefinition definition) throws InvalidServiceDefinitionException; + + protected void checkDefinition(ServiceDefinition definition) throws ServiceRegistrationException { + try{ + String hostname=definition.getHostname(); + List serviceEndpoints=queryServiceEndpoints(); + ServiceEndpoint existing=ISUtils.getByHostnameInCollection(hostname, serviceEndpoints); + if(existing!=null) { + throw new ServiceRegistrationException("Service is already registered"); + } + List gCoreNodes=queryGcoreEndpoints(); + GCoreEndpoint running=ISUtils.getByHostnameInCollection(hostname, gCoreNodes); + if(running==null) throw new ServiceRegistrationException("No GCoreEndpoint found for "+definition); + }catch(ServiceRegistrationException e) { + throw e; + }catch(Throwable t) { + throw new ServiceRegistrationException("Unexpected exception while trying to register "+definition, t); + } + } + + protected ServiceEndpoint prepareEndpoint(ServiceDefinition definition) throws ServiceRegistrationException { + try{ + ServiceEndpoint toCreate=new ServiceEndpoint(); + Profile profile=toCreate.newProfile(); + profile.category(getServiceEndpointCategory()); + profile.description(definition.getDescription()); + profile.name(definition.getName()); + Platform platform=profile.newPlatform(); + platform.name(getServiceEndpointPlatformName()). + version(definition.getMajorVersion()). + minorVersion(definition.getMinorVersion()). + revisionVersion(definition.getReleaseVersion()); + + org.gcube.common.resources.gcore.ServiceEndpoint.Runtime runtime=profile.newRuntime(); + runtime.hostedOn(definition.getHostname()); + + GCoreEndpoint relatedGHN=ISUtils.getByHostnameInCollection(definition.getHostname(), queryGcoreEndpoints()); + + runtime.ghnId(relatedGHN.id()); + runtime.status("READY"); + + return toCreate; + }catch(Throwable t) { + throw new ServiceRegistrationException("Unexpected exception while trying to register "+definition, t); + } + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/CachedObject.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/CachedObject.java new file mode 100644 index 0000000..c38c26f --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/CachedObject.java @@ -0,0 +1,33 @@ +package org.gcube.spatial.data.sdi.engine.impl.is; + +public class CachedObject { + + + + + private long lastUpdate=System.currentTimeMillis(); + + + private T theObject; + + + + + public CachedObject(T theObject) { + super(); + this.theObject = theObject; + } + + public T getTheObject() { + return theObject; + } + + + public boolean isValid(long TTL){ + return System.currentTimeMillis()-lastUpdate accessibleCredentials=new ArrayList(); +// for(Account acc: scopeConfig.getAccounts().values()){ +// accessibleCredentials.add(fromGeoNetworkAccount(acc)); +// } +// +// Credentials adminCredentials=fromGeoNetworkAccount(config.getAdminAccount()); +// // GN Lib doesn't expose ADMIN account type +// adminCredentials.setAccessType(AccessType.ADMIN); +// accessibleCredentials.add(adminCredentials); +// return new GeoNetworkDescriptor(version, baseEndpoint, accessibleCredentials, scopeConfig.getPrivateGroup()+"", scopeConfig.getPublicGroup()+"", "3"); +// }catch(Exception e){ +// log.warn("Unable to gather geonetwork information",e); +// throw new ConfigurationNotFoundException("Unable to gather information on geonetwork. Please contact administrator.",e); +// } +// } + + + + protected static final Credentials fromGeoNetworkAccount(Account toTranslate){ + switch(toTranslate.getType()){ + case CKAN : return new Credentials(toTranslate.getUser(),toTranslate.getPassword(),AccessType.CKAN); + case SCOPE : return new Credentials(toTranslate.getUser(),toTranslate.getPassword(),AccessType.CONTEXT_USER); + default : throw new RuntimeException("Unrecognized account type "+toTranslate); + } + + } + + @Override + protected boolean isSmartGearsMandatory() { + return LocalConfiguration.getFlag(LocalConfiguration.GEONETWORK_MANDATORY_SG); + } + + + protected static final ServiceEndpoint getTheRightServiceEndpoint(Listresources, String endpointName,String priorityProperty){ + ServiceEndpoint toReturn=null; + int priority=1000; + for(ServiceEndpoint resource: resources){ + Iterator points=resource.profile().accessPoints().iterator(); + + while(points.hasNext()){ + AccessPoint point= points.next(); + log.debug(point.toString()); + if(point.name().equals(endpointName)){ + Map properties=point.propertyMap(); + if(properties.containsKey(priorityProperty)){ + int currentPriority=Integer.parseInt(properties.get(priorityProperty).value()); + if(toReturn==null||(currentPriority points=resource.profile().accessPoints().iterator(); + + while(points.hasNext()){ + AccessPoint point= points.next(); + log.debug(point.toString()); + if(point.name().equals(endpointName)){ + Map properties=point.propertyMap(); + if(properties.containsKey(priorityProperty)){ + int currentPriority=Integer.parseInt(properties.get(priorityProperty).value()); + if(toReturn==null||(currentPriority performInstanceCheck(ServiceEndpoint se) { + return Collections.EMPTY_LIST; + } + + @Override + protected void checkDefinitionForServiceType(ServiceDefinition definition) { + log.info("Checking geonetwork for {} ",definition); + // Contact GN + // try to login with credentials + // check priority of other GNs against the defined one + } + + @Override + protected ServiceEndpoint prepareEndpoint(ServiceDefinition definition) throws ServiceRegistrationException { + ServiceEndpoint toReturn= super.prepareEndpoint(definition); + GeoNetworkServiceDefinition gnDefinition=(GeoNetworkServiceDefinition) definition; + + AccessPoint point=new AccessPoint(); + point.address("http://"+definition.getHostname()+"/geonetwork"); + point.credentials(ISUtils.encryptString(definition.getAdminPassword()), "admin"); + point.description("Main Access point"); + point.name(getServiceEndpointAccessPointName()); + + // Priority property + Property priorityProperty=new Property(); + priorityProperty.nameAndValue("priority", gnDefinition.getPriority()+""); + point.properties().add(priorityProperty); + // Suffixes property + Property suffixesProperty=new Property(); + suffixesProperty.nameAndValue("suffixes", ""); + point.properties().add(suffixesProperty); + + toReturn.profile().accessPoints().add(point); + + return toReturn; + } + + + @Override + protected void checkDefinitionType(ServiceDefinition definition) throws InvalidServiceDefinitionException { + if(!definition.getType().equals(Type.GEONETWORK)||!(definition instanceof GeoNetworkServiceDefinition)) + throw new InvalidServiceDefinitionException("Invalid service type [expected "+Type.GEONETWORK+"]. Definition was "+definition); + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/GeoServerClusterRetriever.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/GeoServerClusterRetriever.java new file mode 100644 index 0000000..b3be755 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/GeoServerClusterRetriever.java @@ -0,0 +1,120 @@ +package org.gcube.spatial.data.sdi.engine.impl.is; + +import java.util.Collections; +import java.util.List; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceDefinitionException; +import org.gcube.spatial.data.sdi.model.health.Status; +import org.gcube.spatial.data.sdi.model.services.GeoServerDefinition; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition.Type; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class GeoServerClusterRetriever extends AbstractISModule{ + + +// @Override +// public List ge throws ConfigurationNotFoundException { +// //TODO skip library +// //TODO use both GCoreEndpoints and ServiceEndpoint +// try { +// ArrayList availableInstances=new ArrayList<>(); +// for(ServiceEndpoint ep: getServiceEndpoints()) { +// try{ +// availableInstances.add(translate(ep)); +// }catch(Throwable t) { +// log.warn("Unable to translate ServiceEndpoint [ID : {}].",ep.id(),t); +// } +// } +// }catch(Throwable e){ +// log.warn("Unable to gather geoserver cluster configuration on scope "+ScopeUtils.getCurrentScope(),e); +// throw new ConfigurationNotFoundException("Unable to gather geoserver cluster configuration. Please ontact administrator.",e); +// } +// +// log.info("Retrieving GeoServer cluster configuration under scope {}",ScopeUtils.getCurrentScope()); +// try{ +// GISInterface gis=GISInterface.get(); +// ArrayList availableInstances=new ArrayList<>(); +// for(AbstractGeoServerDescriptor desc: gis.getCurrentCacheElements(true)){ +// try{ +// availableInstances.add(translate(desc)); +// }catch(Throwable t){ +// log.warn("Unable to translate descriptor for endpoint"+desc.getUrl(),t); +// } +// } +// +// return new GeoServerCluster(availableInstances); +// }catch(Exception e){ +// log.warn("Unable to gather geoserver cluster configuration on scope "+ScopeUtils.getCurrentScope(),e); +// throw new ConfigurationNotFoundException("Unable to gather geoserver cluster configuration. Please ontact administrator.",e); +// } +// } + + + @Override + protected boolean isSmartGearsMandatory() { + return LocalConfiguration.getFlag(LocalConfiguration.GEOSERVER_MANDATORY_SG); + } + + + +// private static final GeoServerDescriptor translate(AbstractGeoServerDescriptor desc){ +// Version version=new Version(2,1,2); +// String baseEndpoint=desc.getUrl(); +// List accessibleCredentials=Collections.singletonList(new Credentials(desc.getUser(), desc.getPassword(), AccessType.ADMIN)); +// String confidentialWorkspace=null; +// String contextVisibilityWorkspace=null; +// String sharedWorkspace=null; +// String publicWorkspace=null; +// return new GeoServerDescriptor(version, baseEndpoint, accessibleCredentials, confidentialWorkspace, contextVisibilityWorkspace, sharedWorkspace, publicWorkspace); +// } + + @Override + protected String getGCoreEndpointServiceClass() { + return LocalConfiguration.getProperty(LocalConfiguration.GEOSERVER_GE_SERVICE_CLASS); + } + @Override + protected String getGCoreEndpointServiceName() { + return LocalConfiguration.getProperty(LocalConfiguration.GEOSERVER_GE_SERVICE_NAME); + } + @Override + protected String getManagedServiceType() { + return "GeoServer"; + } + + @Override + protected String getServiceEndpointAccessPointName() { + return LocalConfiguration.getProperty(LocalConfiguration.GEOSERVER_SE_ENDPOINT_NAME); + } + + @Override + protected String getServiceEndpointCategory() { + return LocalConfiguration.getProperty(LocalConfiguration.GEOSERVER_SE_CATEGORY); + } + @Override + protected String getServiceEndpointPlatformName() { + return LocalConfiguration.getProperty(LocalConfiguration.GEOSERVER_SE_PLATFORM); + } + @Override + protected List performInstanceCheck(ServiceEndpoint se) { + return Collections.EMPTY_LIST; + } + + @Override + protected void checkDefinitionForServiceType(ServiceDefinition definition) + throws InvalidServiceDefinitionException { + // Contact GN + // try to login with credentials + } + @Override + protected void checkDefinitionType(ServiceDefinition definition) throws InvalidServiceDefinitionException { + if(!definition.getType().equals(Type.GEOSERVER)||!(definition instanceof GeoServerDefinition)) + throw new InvalidServiceDefinitionException("Invalid service type [expected "+Type.GEOSERVER+"]. Definition was "+definition); + } + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/ISModule.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/ISModule.java new file mode 100644 index 0000000..c4d13a5 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/ISModule.java @@ -0,0 +1,17 @@ +package org.gcube.spatial.data.sdi.engine.impl.is; + +import java.util.List; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceRegistrationException; +import org.gcube.spatial.data.sdi.model.health.ServiceHealthReport; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition; + +public interface ISModule { + + public List getISInformation()throws ConfigurationNotFoundException; + public ServiceHealthReport getHealthReport(); + public String registerService(ServiceDefinition definition) throws ServiceRegistrationException; + public String importHostFromToken(String sourceToken,String host)throws ServiceRegistrationException; +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/ISUtils.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/ISUtils.java new file mode 100644 index 0000000..6434e29 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/ISUtils.java @@ -0,0 +1,233 @@ +package org.gcube.spatial.data.sdi.engine.impl.is; + +import static org.gcube.resources.discovery.icclient.ICFactory.client; +import static org.gcube.resources.discovery.icclient.ICFactory.clientFor; +import static org.gcube.resources.discovery.icclient.ICFactory.queryFor; + +import java.io.ByteArrayOutputStream; +import java.lang.reflect.InvocationTargetException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +import org.gcube.common.encryption.StringEncrypter; +import org.gcube.common.resources.gcore.GCoreEndpoint; +import org.gcube.common.resources.gcore.Resource; +import org.gcube.common.resources.gcore.Resources; +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.informationsystem.publisher.RegistryPublisher; +import org.gcube.informationsystem.publisher.RegistryPublisherFactory; +import org.gcube.resources.discovery.client.api.DiscoveryClient; +import org.gcube.resources.discovery.client.queries.api.SimpleQuery; +import org.gcube.resources.discovery.client.queries.impl.QueryBox; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.NetUtils; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; +import org.gcube.vremanagement.resourcemanager.client.RMBinderLibrary; +import org.gcube.vremanagement.resourcemanager.client.exceptions.InvalidScopeException; +import org.gcube.vremanagement.resourcemanager.client.exceptions.ResourcesCreationException; +import org.gcube.vremanagement.resourcemanager.client.fws.Types.AddResourcesParameters; +import org.gcube.vremanagement.resourcemanager.client.fws.Types.ResourceItem; +import org.gcube.vremanagement.resourcemanager.client.fws.Types.ResourceList; +import org.gcube.vremanagement.resourcemanager.client.proxies.Proxies; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ISUtils { + + public static List queryForServiceEndpoints(String category, String platformName){ + log.debug("Querying for Service Endpoints [category : {} , platformName : {}, currentScope : {} ]",category,platformName,ScopeUtils.getCurrentScope()); + + SimpleQuery query = queryFor(ServiceEndpoint.class); + + query.addCondition("$resource/Profile/Category/text() eq '"+category+"'") + .addCondition("$resource/Profile/Platform/Name/text() eq '"+platformName+"'"); + // .setResult("$resource/Profile/AccessPoint"); + + DiscoveryClient client = clientFor(ServiceEndpoint.class); + + return client.submit(query); + } + + public static List queryForGCoreEndpoint(String serviceClass,String serviceName){ + log.debug("Querying for GCore Endpoints [ServiceClass : {} , ServiceName : {}, currentScope : {} ]",serviceClass,serviceName,ScopeUtils.getCurrentScope()); + + + SimpleQuery query =queryFor(GCoreEndpoint.class); + query.addCondition("$resource/Profile/ServiceClass/text() eq '"+serviceClass+"'") + .addCondition("$resource/Profile/ServiceName/text() eq '"+serviceName+"'"); + // .setResult("$resource/Profile/AccessPoint"); + + DiscoveryClient client = clientFor(GCoreEndpoint.class); + + return client.submit(query); + } + + + public static T getByHostnameInCollection(String hostname, Collection toCheckList) throws UnknownHostException { + for(T gc:toCheckList) { + String currentHostToCheck=getHost(gc); + if(NetUtils.isSameHost(currentHostToCheck, hostname)) return gc; + } + return null; + } + + + public static String getHost(Resource res) { + if(res instanceof GCoreEndpoint) + return (((GCoreEndpoint)res).profile().endpoints().iterator().next().uri().getHost()); + else return (((ServiceEndpoint)res).profile().runtime().hostedOn()); + } + + public static List querySEByHostname(String category,String platformName,String hostname){ + log.debug("Querying Service Endpoints by hostname [category : {} , platformName : {}, currentScope : {}, hostname {} ]",category,platformName,ScopeUtils.getCurrentScope(),hostname); + + SimpleQuery query = queryFor(ServiceEndpoint.class); + + query.addCondition("$resource/Profile/Category/text() eq '"+category+"'") + .addCondition("$resource/Profile/Platform/Name/text() eq '"+platformName+"'") + .addCondition("$resource/Profile/Runtime/HostedOn/text() eq '"+hostname+"'"); + // .setResult("$resource/Profile/AccessPoint"); + + DiscoveryClient client = clientFor(ServiceEndpoint.class); + + return client.submit(query); + } + + + public static List queryById(String id) { + DiscoveryClient client = client(); + String queryString ="declare namespace ic = 'http://gcube-system.org/namespaces/informationsystem/registry'; "+ + "for $profiles in collection('/db/Profiles')//Document/Data/ic:Profile/Resource "+ + "where $profiles/ID/text() eq '"+id+"'"+ + " return $profiles"; + return client.submit(new QueryBox(queryString)); + } + + + public static ServiceEndpoint querySEById(String id) { + SimpleQuery query = queryFor(ServiceEndpoint.class); + + query.addCondition("$resource/ID/text() eq '"+id+"'"); + + DiscoveryClient client = clientFor(ServiceEndpoint.class); + + return client.submit(query).get(0); + } + + public static String registerService(ServiceEndpoint toRegister) { + RegistryPublisher rp=RegistryPublisherFactory.create(); + if(log.isDebugEnabled()) + Resources.print(toRegister); + Resource r=rp.create(toRegister); + return r.id(); + } + + + public static String addToScope(ServiceEndpoint se,GCoreEndpoint gc, String targetScope) throws ResourcesCreationException, InvalidScopeException { + log.trace("Publishing GC [ID : {}, Sc : {}, Sn {}, GHN-ID : {} ], SE [ID : {}, name : {}] to Scope {} from Scope {}", + gc.id(), gc.profile().serviceClass(),gc.profile().serviceName(),gc.profile().ghnId(), + se.id(),se.profile().name(),targetScope,ScopeUtils.getCurrentScope()); + + + AddResourcesParameters params=new AddResourcesParameters(); + ResourceList resourceList=new ResourceList(); + ArrayList list=new ArrayList<>(); + + ResourceItem ghnItem=new ResourceItem(); + ghnItem.id=gc.profile().ghnId(); + ghnItem.type="GHN"; + list.add(ghnItem); + + ResourceItem geItem=new ResourceItem(); + geItem.id=gc.id(); + geItem.type="RunningInstance"; + list.add(geItem); + + ResourceItem seItem=new ResourceItem(); + seItem.id=se.id(); + seItem.type="RuntimeResource"; + list.add(seItem); + + resourceList.setResource(list); + params.setTargetScope(targetScope); + params.setResources(resourceList); + + RMBinderLibrary library=Proxies.binderService().build(); + return library.addResources(params); + } + + + public static String decryptString(String toDecrypt){ + try{ + return StringEncrypter.getEncrypter().decrypt(toDecrypt); + }catch(Exception e) { + throw new RuntimeException("Unable to decrypt : "+toDecrypt,e); + } + } + + public static String encryptString(String toEncrypt){ + try{ + return StringEncrypter.getEncrypter().encrypt(toEncrypt); + }catch(Exception e) { + throw new RuntimeException("Unable to encrypt : "+toEncrypt,e); + } + } + + + public static ServiceEndpoint update(ServiceEndpoint toUpdate) { + RegistryPublisher rp=RegistryPublisherFactory.create(); + try{ + return rp.update(toUpdate); + }catch(RuntimeException t) { + log.warn("Unable to update resource {} ",toUpdate.id()); + log.debug("Updated resource is {} ",marshal(toUpdate)); + throw t; + } + } + + public static ServiceEndpoint updateAndWait(ServiceEndpoint toUpdate) { + boolean equals=true; + boolean timeoutReached=false; + long timeout=LocalConfiguration.getTTL(LocalConfiguration.IS_REGISTRATION_TIMEOUT); + log.trace("Going to update {}. Timeout is {} ",toUpdate.id(),timeout); + String toUpdateString=marshal(toUpdate); + update(toUpdate); + long updateTime=System.currentTimeMillis(); + String updatedString=null; + do { + try { + Thread.sleep(500); + } catch (InterruptedException e) {} + updatedString=marshal(querySEById(toUpdate.id())); + equals=toUpdateString.equals(updatedString); + timeoutReached=(System.currentTimeMillis()-updateTime)>timeout; + }while(!equals&&(!timeoutReached)); + if(timeoutReached) log.warn("Timeout reached. Check if {} is updated ",toUpdate.id()); + return querySEById(toUpdate.id()); + } + + + public static String marshal(Resource res) { + ByteArrayOutputStream stream=new ByteArrayOutputStream(); + Resources.marshal(res, stream); + return stream.toString(); + } + + + public static HashSet getSiblingsScopesInResource(Resource res,String scope){ + HashSet toReturn=new HashSet(); + String parent=ScopeUtils.getParentScope(scope); + if (parent!=null) + for(String resourceScope:res.scopes().asCollection()) + if(!resourceScope.equals(scope)) { + String resourceScopeParent=ScopeUtils.getParentScope(resourceScope); + if((resourceScopeParent!=null)&&(resourceScopeParent.equals(parent))) toReturn.add(resourceScope); + } + return toReturn; + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/ThreddsRetriever.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/ThreddsRetriever.java new file mode 100644 index 0000000..4f5028d --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/is/ThreddsRetriever.java @@ -0,0 +1,209 @@ +package org.gcube.spatial.data.sdi.engine.impl.is; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; +import org.gcube.common.resources.gcore.common.Platform; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.NetUtils; +import org.gcube.spatial.data.sdi.engine.impl.faults.InvalidServiceDefinitionException; +import org.gcube.spatial.data.sdi.model.credentials.AccessType; +import org.gcube.spatial.data.sdi.model.credentials.Credentials; +import org.gcube.spatial.data.sdi.model.health.Level; +import org.gcube.spatial.data.sdi.model.health.Status; +import org.gcube.spatial.data.sdi.model.service.ThreddsDescriptor; +import org.gcube.spatial.data.sdi.model.service.Version; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition.Type; +import org.gcube.spatial.data.sdi.model.services.ThreddsDefinition; + +import lombok.extern.slf4j.Slf4j; +@Slf4j +public class ThreddsRetriever extends AbstractISModule { + +// @Override +// public ThreddsDescriptor getObject() throws ConfigurationNotFoundException{ +// log.info("Loading Thredds information from IS. Current Scope is {} ",ScopeUtils.getCurrentScope()); +// +// // Try to look for GCore Endpoints first +// +//// List gCoreEndpoints=getGcoreEndpoints(); +//// if(gCoreEndpoints!=null&&!gCoreEndpoints.isEmpty()){ +//// log.debug("Found {} GCore Endpoints ",gCoreEndpoints.size()); +//// for(int i=0;i threddsSE=getServiceEndpoints(); +// if(threddsSE!=null&&!threddsSE.isEmpty()){ +// log.debug("Found {} Service Endpoints ",threddsSE.size()); +// for(int i=0;i checkStatuses=new ArrayList<>(); +// try { +// +// log.trace("Checking Thredds heatlh under context {} ",ScopeUtils.getCurrentScope()); +// //Check if existing +// List gCoreEndpoints=getGcoreEndpoints(); +// List serviceEndpoints=getServiceEndpoints(); +// log.debug("Found {} GC Endpoints and {} SE Endpoints",gCoreEndpoints.size(),serviceEndpoints.size()); +// +// if(serviceEndpoints.isEmpty()) +// if(gCoreEndpoints.isEmpty())checkStatuses.add(new Status("No Thredds service found in context "+ScopeUtils.getCurrentScope(),Level.ERROR)); +// else checkStatuses.add(new Status("Unregistered Thredds instances found. Check following messages",Level.ERROR)); +// +// //For each GC check for missing SE +// for(GCoreEndpoint gc:gCoreEndpoints) { +// String hostname= gc.profile().endpoints().iterator().next().uri().getHost(); +// if(ISUtils.getGCEByHostname(hostname, serviceEndpoints)==null) { +// String msg="Found unregistered Thredds hosted on "+hostname; +// log.debug(msg); +// checkStatuses.add(new Status(msg,Level.WARNING)); +// } +// } +// +// for(ServiceEndpoint se: serviceEndpoints) { +// +// } +// }catch(Throwable t) { +// log.error("Unable to perform checks", t); +// checkStatuses.add(new Status("Internal error while checking Thredds Status.",Level.ERROR)); +// } +// return new ServiceHealthReport(checkStatuses); +// } + + @Override + protected String getGCoreEndpointServiceClass() { + return LocalConfiguration.getProperty(LocalConfiguration.THREDDS_GE_SERVICE_CLASS); + } + @Override + protected String getGCoreEndpointServiceName() { + return LocalConfiguration.getProperty(LocalConfiguration.THREDDS_GE_SERVICE_NAME); + } + + @Override + protected String getManagedServiceType() { + return "THREDDS"; + } + + @Override + protected String getServiceEndpointCategory() { + return LocalConfiguration.getProperty(LocalConfiguration.THREDDS_SE_CATEGORY); + } + @Override + protected String getServiceEndpointPlatformName() { + return LocalConfiguration.getProperty(LocalConfiguration.THREDDS_SE_PLATFORM); + } + @Override + protected String getServiceEndpointAccessPointName() { + return LocalConfiguration.getProperty(LocalConfiguration.THREDDS_SE_ENDPOINT_NAME); + } + + @Override + protected boolean isSmartGearsMandatory() { + return LocalConfiguration.getFlag(LocalConfiguration.THREDDS_MANDATORY_SG); + } + + @Override + protected List performInstanceCheck(ServiceEndpoint se) { + ArrayList toReturn=new ArrayList(); + + String hostname=se.profile().runtime().hostedOn(); + try { + log.trace("Checking thredds hosted on {} ",hostname); + String publicCatalogUrl="www."+hostname+"/thredds/catalog/public/netcdf/catalog.html"; + if(!NetUtils.isUp(publicCatalogUrl)) + toReturn.add(new Status("Unreachable default THREDDS catalog at "+publicCatalogUrl,Level.ERROR)); + else { + +// +// +// DataTransferClient client=DataTransferClient.getInstanceByEndpoint(hostname); +// //check SIS plugin presence +// boolean found=false; +// for(PluginDescription desc: client.getDestinationCapabilities().getAvailablePlugins()) +// if(desc.getId().equals("SIS/GEOTK")) { +// found=true; +// break; +// } +// if(!found) toReturn.add(new Status("SIS/GEOTK plugin for DataTransfer service not found on "+hostname, Level.ERROR)); + + } + }catch(IOException e) { + String msg="Unable to check thredds instance hosted on "+hostname; + log.warn(msg); + log.debug("Exception was ",e); + toReturn.add(new Status(msg,Level.WARNING)); +// } catch (DataTransferException e) { +// String msg="DataTransfer not found in host "+hostname; +// log.warn(msg); +// log.debug("Exception was ",e); +// toReturn.add(new Status(msg,Level.ERROR)); + } + return toReturn; + } + + + +// private static final ThreddsConfiguration translate(GCoreEndpoint toTranslate){ +//// +//// ThreddsConfiguration toReturn=new ThreddsConfiguration(version, baseEndpoint, accessibleCredentials); +// return null; +// } + + private static final ThreddsDescriptor translate(ServiceEndpoint toTranslate){ + Platform platform=toTranslate.profile().platform(); + Version version=new Version(platform.version(),platform.minorVersion(),platform.revisionVersion()); + AccessPoint access=toTranslate.profile().accessPoints().iterator().next(); + Credentials credentials=new Credentials(access.username(),access.password(),AccessType.ADMIN); + return new ThreddsDescriptor(version, access.address(), Collections.singletonList(credentials)); + } + + + @Override + protected void checkDefinitionForServiceType(ServiceDefinition definition) + throws InvalidServiceDefinitionException { + // TODO Auto-generated method stub + + } + + @Override + protected void checkDefinitionType(ServiceDefinition definition) throws InvalidServiceDefinitionException { + if(!definition.getType().equals(Type.THREDDS)||!(definition instanceof ThreddsDefinition)) + throw new InvalidServiceDefinitionException("Invalid service type [expected "+Type.THREDDS+"]. Definition was "+definition); + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/CommonMetadataPieces.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/CommonMetadataPieces.java new file mode 100644 index 0000000..db86d0c --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/CommonMetadataPieces.java @@ -0,0 +1,16 @@ +package org.gcube.spatial.data.sdi.engine.impl.metadata; + +public class CommonMetadataPieces { + + public static final String resourceIdentifier=" " + + " %s" + + " " + + ""; + + public static final String fileIdentifier="" + + " %s "; + + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/GenericTemplates.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/GenericTemplates.java new file mode 100644 index 0000000..576388f --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/GenericTemplates.java @@ -0,0 +1,15 @@ +package org.gcube.spatial.data.sdi.engine.impl.metadata; + +public class GenericTemplates { + + public static class ThreddsCatalogTemplate{ + public static final String FILENAME="thredds_catalog.ftlx"; + + public static final String CATALOG_PATH="CatalogPath"; + public static final String LOCATION="Location"; + public static final String DATASET_SCAN_NAME="DataSetScanName"; + public static final String DATASET_SCAN_ID="DataSetScanID"; + public static final String AUTHORITY_URL="AuthorityURL"; + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/MetadataHandler.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/MetadataHandler.java new file mode 100644 index 0000000..0c6c060 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/MetadataHandler.java @@ -0,0 +1,85 @@ +package org.gcube.spatial.data.sdi.engine.impl.metadata; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.List; +import java.util.UUID; + +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.gcube.common.resources.gcore.utils.XPathHelper; +import org.gcube.spatial.data.sdi.engine.impl.metadata.templates.AbstractMetadataTemplate.InsertionPoint; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MetadataHandler { + + private Document document=null; + private String metaUUID=null; + private XPathHelper helper; + public MetadataHandler(File xmlFile){ + // Get document owner + Element documentNode=null; + try{ + InputStream inputStream= new FileInputStream(xmlFile); + Reader reader = new InputStreamReader(inputStream,"UTF-8"); + + InputSource is = new InputSource(reader); + documentNode = MetadataUtils.docBuilder.parse(is).getDocumentElement(); + document=documentNode.getOwnerDocument(); + + helper=MetadataUtils.getHelper(document); + + // document = (Document)xpath.evaluate("/", inputSource, XPathConstants.NODE); + }catch(Exception e){ + // throw e; + throw new RuntimeException("Unable to fix : unable to get Document",e); + } + + + } + + public String getUUID() throws SAXException, IOException{ + //Set | get meta UUID + if(metaUUID==null){ + log.debug("Managing metadata ID.. "); + + + List metaUUIDList=helper.evaluate("//gmd:fileIdentifier/gco:CharacterString/text()"); + if(metaUUIDList.isEmpty()){ + metaUUID=UUID.randomUUID().toString(); + log.debug("Stting uuid {} ",metaUUID); + MetadataUtils.addContent("gmd:MD_Metadata",document,String.format(CommonMetadataPieces.fileIdentifier, metaUUID),helper,MetadataUtils.Position.first_child); + }else { + metaUUID=metaUUIDList.get(0); + log.debug("Found meta UUID {} ",metaUUID); + } + } + return metaUUID; + } + + + public void addContent(String content, InsertionPoint insertion) throws SAXException, IOException{ + MetadataUtils.addContent(insertion.getElementReference(), document, content, helper, insertion.getPosition()); + } + + public File writeOut() throws IOException, TransformerException{ + DOMSource source = new DOMSource(document); + File output=File.createTempFile("meta_", ".xml"); + output.createNewFile(); + StreamResult result = new StreamResult(output); + MetadataUtils.transformer.transform(source, result); + return output; + } +} \ No newline at end of file diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/MetadataTemplateManagerImpl.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/MetadataTemplateManagerImpl.java new file mode 100644 index 0000000..0d36d72 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/MetadataTemplateManagerImpl.java @@ -0,0 +1,181 @@ +package org.gcube.spatial.data.sdi.engine.impl.metadata; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.annotation.PostConstruct; +import javax.inject.Singleton; +import javax.xml.transform.TransformerException; + +import org.apache.commons.io.IOUtils; +import org.gcube.smartgears.context.application.ApplicationContext; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.TemplateManager; +import org.gcube.spatial.data.sdi.engine.impl.metadata.templates.AbstractMetadataTemplate; +import org.gcube.spatial.data.sdi.engine.impl.metadata.templates.InvalidTemplateInvocationException; +import org.gcube.spatial.data.sdi.engine.impl.metadata.templates.ThreddsOnlineTemplate; +import org.gcube.spatial.data.sdi.model.metadata.TemplateCollection; +import org.gcube.spatial.data.sdi.model.metadata.TemplateDescriptor; +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocation; + +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateExceptionHandler; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Singleton +public class MetadataTemplateManagerImpl implements TemplateManager { + + + private static Configuration cfg; + +// private static ArrayList templateDescriptors=new ArrayList<>(); + + private static HashMap availableMetadataTemplates=new HashMap<>(); + + + private static TemplateCollection metadataTemplateDescriptors; + + @PostConstruct + public void defaultInit() { + log.info("Default Initialization"); + init(LocalConfiguration.getTemplateConfigurationObject()); + } + + + + public void init(Object configurationObject) { + + log.debug("Configuring with {} ",configurationObject); + + // Create your Configuration instance, and specify if up to what FreeMarker + // version (here 2.3.25) do you want to apply the fixes that are not 100% + // backward-compatible. See the Configuration JavaDoc for details. + cfg = new Configuration(Configuration.VERSION_2_3_25); + + if(configurationObject instanceof ApplicationContext){ + log.debug("Configuration is Context : {} ",configurationObject); + cfg.setServletContextForTemplateLoading(((ApplicationContext)configurationObject).application(), + LocalConfiguration.getProperty(LocalConfiguration.TEMPLATE_FOLDER)); + }else if (configurationObject instanceof File){ + try{ + cfg.setDirectoryForTemplateLoading((File)configurationObject); + }catch(IOException e){ + throw new RuntimeException(e); + } + + }else throw new RuntimeException("Invalid configuration object"); + + // Set the preferred charset template files are stored in. UTF-8 is + // a good choice in most applications: + cfg.setDefaultEncoding("UTF-8"); + + // Sets how errors will appear. + // During web page *development* TemplateExceptionHandler.HTML_DEBUG_HANDLER is better. + cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + + // Don't log exceptions inside FreeMarker that it will thrown at you anyway: + cfg.setLogTemplateExceptions(false); + + + // availableTemplates.add(new TemplateDescriptor("THREDDS-ONLINE", "Thredds online resources", "Template for online resources exposed by thredds.", "http://sdi-d4s.d4science.org")); + + + ThreddsOnlineTemplate tpl=new ThreddsOnlineTemplate(); + availableMetadataTemplates.put(tpl.getDescriptor().getId(), tpl); + ArrayList metadataTemplates=new ArrayList(); + metadataTemplates.add(tpl.getDescriptor()); + log.debug("Loaded metadata templates : "); + for(TemplateDescriptor desc: metadataTemplates) + log.debug(desc.toString()); + metadataTemplateDescriptors=new TemplateCollection(new HashSet<>(metadataTemplates)); + + } + + + + + @Override + public TemplateCollection getAvailableMetadataTemplates() { + return metadataTemplateDescriptors; + } + + @Override + public TemplateApplicationReport applyMetadataTemplates(File original, Set invocations) throws IOException, TransformerException { + log.debug("Applying template invocations {} to {} ",invocations,original.getAbsolutePath()); + TemplateApplicationReport report=new TemplateApplicationReport(); + report.setRequestedInvocations(invocations); + HashSet appliedTemplates=new HashSet<>(); + MetadataHandler handler=new MetadataHandler(original); + for(TemplateInvocation invocation:invocations){ + try{ + applyTemplate(original, invocation,handler); + appliedTemplates.add(invocation.getToInvokeTemplateID()); + }catch(Throwable t){ + log.warn("Unable to apply template {} ",invocation.getToInvokeTemplateID()); + log.debug("StackTrace : ",t); + } + } + log.debug("Writing out result.."); + report.setGeneratedFilePath(handler.writeOut().getAbsolutePath()); + report.setAppliedTemplates(appliedTemplates); + return report; + } + + private static void applyTemplate(File original,TemplateInvocation invocation,MetadataHandler handler) throws Exception{ + log.debug("Instantiating "+invocation); + AbstractMetadataTemplate tpl=availableMetadataTemplates.get(invocation.getToInvokeTemplateID()); + if(tpl==null) throw new InvalidTemplateInvocationException("Template with ID "+invocation.getToInvokeTemplateID()+" was not found"); + Writer out=null; + try{ + Template temp = cfg.getTemplate(tpl.getFileName()); + ByteArrayOutputStream baos=new ByteArrayOutputStream(); + out=new OutputStreamWriter(baos); + temp.process(tpl.getInstantiationRequest(handler,invocation), out); + out.flush(); + String instantiatedTemplate= baos.toString(StandardCharsets.UTF_8.toString()); + + //apply to original + handler.addContent(instantiatedTemplate, tpl.getInsertionPoint()); + } catch (Exception e) { + log.error("Unable to apply template. Invocation was {} ",invocation,e); + throw e; + }finally{ + if(out!=null) + IOUtils.closeQuietly(out); + } + } + + + @Override + public File generateFromTemplate(Map parameters, String template) throws Exception { + Writer out=null; + try{ + log.info("Generating from template {}. Parameters are {} ",template,parameters); + Template temp = cfg.getTemplate(template); + File toReturn=File.createTempFile(template, ".xml"); + out=new FileWriter(toReturn); + temp.process(parameters, out); + out.flush(); + return toReturn; + } catch (Exception e) { + log.error("Unable to apply template{}. Parameters were {} ",template,parameters,e); + throw e; + }finally{ + if(out!=null) + IOUtils.closeQuietly(out); + } + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/MetadataUtils.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/MetadataUtils.java new file mode 100644 index 0000000..c37474f --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/MetadataUtils.java @@ -0,0 +1,126 @@ +package org.gcube.spatial.data.sdi.engine.impl.metadata; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; + +import org.gcube.common.resources.gcore.utils.XPathHelper; +import org.gcube.portlets.user.uriresolvermanager.UriResolverManager; +import org.gcube.portlets.user.uriresolvermanager.exception.IllegalArgumentException; +import org.gcube.portlets.user.uriresolvermanager.exception.UriResolverMapException; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +public class MetadataUtils { + + public static Transformer transformer =null; + public static DocumentBuilder docBuilder =null; + + + static HashMap namespaces=new HashMap(); + + static{ + try{ + DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + + docBuilder = factory.newDocumentBuilder(); + + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformer = transformerFactory.newTransformer(); + + + namespaces.put("gmd", "http://www.isotc211.org/2005/gmd"); + namespaces.put("gco", "http://www.isotc211.org/2005/gco"); + namespaces.put("fra", "http://www.cnig.gouv.fr/2005/fra"); + namespaces.put("xlink", "http://www.w3.org/1999/xlink"); + namespaces.put("gml", "http://www.opengis.net/gml"); + namespaces.put("xsi", "http://www.w3.org/2001/XMLSchema-instance"); + namespaces.put("gmi", "http://www.isotc211.org/2005/gmi"); + namespaces.put("gmx", "http://www.isotc211.org/2005/gmx"); + + + + + }catch(Exception e){ + throw new RuntimeException("Unable to init Fixer ",e); + } + } + + + public static enum Position{ + sibling_after,sibling_before,first_child,last_child,replace + } + + public static XPathHelper getHelper(Node root){ + XPathHelper toReturn =new XPathHelper(root); + for(Entry entry:namespaces.entrySet()) + toReturn.addNamespace(entry.getKey(), entry.getValue()); + return toReturn; + } + + + public static String readFile(String path) throws IOException{ + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded); + } + + public static String getGisLinkByUUID(String uuid) throws UriResolverMapException, IllegalArgumentException { + Map params=new HashMap(); + params.put("scope", ScopeUtils.getCurrentScope()); + params.put("gis-UUID", uuid); + UriResolverManager resolver = new UriResolverManager("GIS"); + String toReturn= resolver.getLink(params, false); + return toReturn; + } + + public static void addContent(String path, Document doc, String toAddContent, XPathHelper documentHelper,Position position) throws SAXException, IOException{ + NodeList nodelist=documentHelper.evaluateForNodes(path); + if(nodelist==null||nodelist.getLength()==0) throw new RuntimeException("Path "+path+" not found in document"); +// if(nodelist.getLength()>1) throw new RuntimeException("Invalid Path "+path+"."+nodelist.getLength()+" entries found"); + Node targetNode=nodelist.item(0); + + Document online=docBuilder.parse(new ByteArrayInputStream(toAddContent.getBytes())); + Node toAdd=doc.importNode(online.getDocumentElement(), true); + switch(position){ + case first_child: { + targetNode.insertBefore(toAdd, targetNode.getFirstChild()); + break; + } + case last_child:{targetNode.appendChild(toAdd); + break;} + case replace : { + Node parent=targetNode.getParentNode(); + parent.replaceChild(toAdd, targetNode); + break; + } + case sibling_after :{ + Node currentlyNext=targetNode.getNextSibling(); + Node parent=targetNode.getParentNode(); + if(currentlyNext!=null)parent.insertBefore(toAdd, currentlyNext); + else parent.appendChild(toAdd); + break; + } + case sibling_before :{ + Node parent=targetNode.getParentNode(); + parent.insertBefore(toAdd, targetNode); + break; + } + } + + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/TemplateApplicationReport.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/TemplateApplicationReport.java new file mode 100644 index 0000000..4ff49c9 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/TemplateApplicationReport.java @@ -0,0 +1,15 @@ +package org.gcube.spatial.data.sdi.engine.impl.metadata; + +import java.util.Set; + +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocation; + +import lombok.Data; + +@Data +public class TemplateApplicationReport { + + private String generatedFilePath; + private Set appliedTemplates; + private Set requestedInvocations; +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/templates/AbstractMetadataTemplate.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/templates/AbstractMetadataTemplate.java new file mode 100644 index 0000000..4b9287c --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/templates/AbstractMetadataTemplate.java @@ -0,0 +1,49 @@ +package org.gcube.spatial.data.sdi.engine.impl.metadata.templates; + +import java.util.List; + +import org.gcube.spatial.data.sdi.engine.impl.metadata.MetadataHandler; +import org.gcube.spatial.data.sdi.engine.impl.metadata.MetadataUtils.Position; +import org.gcube.spatial.data.sdi.model.ParameterType; +import org.gcube.spatial.data.sdi.model.metadata.TemplateDescriptor; +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocation; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@AllArgsConstructor +public abstract class AbstractMetadataTemplate { + + + + @Getter + @Setter + @ToString + @AllArgsConstructor + public static class InsertionPoint{ + private Position position; + private String elementReference; + } + + + private String fileName; + private InsertionPoint insertionPoint; + private TemplateDescriptor descriptor; + + public abstract T getInstantiationRequest(MetadataHandler original, TemplateInvocation invocation) throws InvalidTemplateInvocationException,Exception; + + protected String getParameter(String parameterName, List parameters, boolean mandatory,String defaultValue)throws InvalidTemplateInvocationException{ + + //if collection not empty look for it + if(!(parameters==null || parameters.isEmpty())) + for(ParameterType param:parameters) + if(param.getName().equals(parameterName)) return param.getValue(); + + //nothing found.. + if(mandatory) throw new InvalidTemplateInvocationException("Missing parameter "+parameterName+"."); + else return defaultValue; + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/templates/InvalidTemplateInvocationException.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/templates/InvalidTemplateInvocationException.java new file mode 100644 index 0000000..6ac74fa --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/templates/InvalidTemplateInvocationException.java @@ -0,0 +1,36 @@ +package org.gcube.spatial.data.sdi.engine.impl.metadata.templates; + +public class InvalidTemplateInvocationException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 8921135030360257131L; + + public InvalidTemplateInvocationException() { + super(); + // TODO Auto-generated constructor stub + } + + public InvalidTemplateInvocationException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + public InvalidTemplateInvocationException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public InvalidTemplateInvocationException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public InvalidTemplateInvocationException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/templates/ThreddsOnlineTemplate.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/templates/ThreddsOnlineTemplate.java new file mode 100644 index 0000000..9e73c7f --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/engine/impl/metadata/templates/ThreddsOnlineTemplate.java @@ -0,0 +1,66 @@ +package org.gcube.spatial.data.sdi.engine.impl.metadata.templates; + +import java.util.ArrayList; + +import org.gcube.spatial.data.sdi.engine.impl.metadata.MetadataHandler; +import org.gcube.spatial.data.sdi.engine.impl.metadata.MetadataUtils; +import org.gcube.spatial.data.sdi.engine.impl.metadata.MetadataUtils.Position; +import org.gcube.spatial.data.sdi.engine.impl.metadata.templates.ThreddsOnlineTemplate.ThreddsOnlineRequest; +import org.gcube.spatial.data.sdi.model.ParameterType; +import org.gcube.spatial.data.sdi.model.metadata.TemplateDescriptor; +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocation; +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocationBuilder; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; + +public class ThreddsOnlineTemplate extends AbstractMetadataTemplate { + + + + + private static ArrayList EXPECTED_PARAMETERS=new ArrayList(); + private static String TEMPLATE_ID=TemplateInvocationBuilder.THREDDS_ONLINE.ID; + private static String TEMPLATE_NAME="Thredds Online Resources"; + private static String FILENAME="ThreddsOnlineResources.ftlx"; + private static InsertionPoint INSERTION=new InsertionPoint(Position.sibling_after, "//gmd:identificationInfo"); + private static TemplateDescriptor DESCRIPTOR; + + static { + EXPECTED_PARAMETERS.add(new ParameterType(TemplateInvocationBuilder.THREDDS_ONLINE.CATALOG, "The thredds catalog name")); + EXPECTED_PARAMETERS.add(new ParameterType(TemplateInvocationBuilder.THREDDS_ONLINE.FILENAME, "The dataset's file name")); + EXPECTED_PARAMETERS.add(new ParameterType(TemplateInvocationBuilder.THREDDS_ONLINE.HOSTNAME, "Thredds hostname")); + + DESCRIPTOR=new TemplateDescriptor(TEMPLATE_ID, TEMPLATE_NAME, "Template for online resources exposed by thredds.", "http://sdi-d4s.d4science.org",EXPECTED_PARAMETERS); + } + + + public ThreddsOnlineTemplate() { + super(FILENAME, INSERTION, DESCRIPTOR); + } + + + @Getter + @AllArgsConstructor + @ToString + public static class ThreddsOnlineRequest{ + private String hostname; + private String catalog; + private String filename; + private String gisViewerLink; + } + + @Override + public ThreddsOnlineRequest getInstantiationRequest(MetadataHandler handler, TemplateInvocation invocation) throws InvalidTemplateInvocationException,Exception{ + if(!invocation.getToInvokeTemplateID().equals(TEMPLATE_ID)) throw new InvalidTemplateInvocationException("Invalid template ID : "+invocation.getToInvokeTemplateID()); + String filename =getParameter(TemplateInvocationBuilder.THREDDS_ONLINE.FILENAME, invocation.getTemplateParameters(), true, null); + String catalog =getParameter(TemplateInvocationBuilder.THREDDS_ONLINE.CATALOG, invocation.getTemplateParameters(), true, null); + String hostname =getParameter(TemplateInvocationBuilder.THREDDS_ONLINE.HOSTNAME, invocation.getTemplateParameters(), true, null); + String uuid=handler.getUUID(); + String gisLink=MetadataUtils.getGisLinkByUUID(uuid); + return new ThreddsOnlineRequest(hostname, catalog, filename, gisLink); + + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/CatalogDescriptor.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/CatalogDescriptor.java new file mode 100644 index 0000000..1c654a9 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/CatalogDescriptor.java @@ -0,0 +1,25 @@ +package org.gcube.spatial.data.sdi.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@RequiredArgsConstructor +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class CatalogDescriptor { + + @NonNull + private String catalogURL; + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/ScopeConfiguration.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/ScopeConfiguration.java new file mode 100644 index 0000000..d9473ad --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/ScopeConfiguration.java @@ -0,0 +1,41 @@ +package org.gcube.spatial.data.sdi.model; + +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.gcube.spatial.data.sdi.model.service.GeoNetworkDescriptor; +import org.gcube.spatial.data.sdi.model.service.GeoServerDescriptor; +import org.gcube.spatial.data.sdi.model.service.ThreddsDescriptor; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@NoArgsConstructor +@RequiredArgsConstructor +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class ScopeConfiguration { + + + + @NonNull + private String contextName; + + @NonNull + private List geonetworkConfiguration; + @NonNull + private List geoserverClusterConfiguration; + @NonNull + private List threddsConfiguration; + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/HealthReport.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/HealthReport.java new file mode 100644 index 0000000..68f4cb6 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/HealthReport.java @@ -0,0 +1,32 @@ +package org.gcube.spatial.data.sdi.model.health; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class HealthReport { + + private Level overallStatus; + + private String context; + + private ServiceHealthReport thredds; + private ServiceHealthReport geonetwork; + private ServiceHealthReport geoserverCluster; + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/Level.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/Level.java new file mode 100644 index 0000000..ee029bd --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/Level.java @@ -0,0 +1,8 @@ +package org.gcube.spatial.data.sdi.model.health; + +import javax.xml.bind.annotation.XmlEnum; + +@XmlEnum +public enum Level{ + WARNING,ERROR,OK +} \ No newline at end of file diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/ServiceHealthReport.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/ServiceHealthReport.java new file mode 100644 index 0000000..ddb77d3 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/ServiceHealthReport.java @@ -0,0 +1,48 @@ +package org.gcube.spatial.data.sdi.model.health; + +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class ServiceHealthReport { + + private Level overallStatus; + + private List checkReports; + + public ServiceHealthReport(List checkReports) { + super(); + this.checkReports = checkReports; + overallStatus =Level.OK; + for(Status st:checkReports) + if(st.getLevel().equals(Level.ERROR)) { + overallStatus=Level.ERROR; + break; + } + else if(st.getLevel().equals(Level.WARNING)&&(overallStatus.equals(Level.OK))) + overallStatus=Level.WARNING; + + + } + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/Status.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/Status.java new file mode 100644 index 0000000..d9fe4f6 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/health/Status.java @@ -0,0 +1,28 @@ +package org.gcube.spatial.data.sdi.model.health; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class Status { + + private String message; + + + private Level level; +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/GeoNetworkDescriptor.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/GeoNetworkDescriptor.java new file mode 100644 index 0000000..627e833 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/GeoNetworkDescriptor.java @@ -0,0 +1,55 @@ +package org.gcube.spatial.data.sdi.model.service; + +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.gcube.spatial.data.sdi.model.credentials.Credentials; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.Setter; +import lombok.ToString; + + +@Getter +@Setter +@ToString +@NoArgsConstructor +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class GeoNetworkDescriptor extends GeoServiceDescriptor{ + + + + + public GeoNetworkDescriptor(Version version, String baseEndpoint, List accessibleCredentials, + String contextGroup, String defaultGroup, String sharedGroup, String confidentialGroup, String publicGroup, + Integer priority) { + super(version, baseEndpoint, accessibleCredentials); + this.contextGroup = contextGroup; + this.defaultGroup = defaultGroup; + this.sharedGroup = sharedGroup; + this.confidentialGroup = confidentialGroup; + this.publicGroup = publicGroup; + this.priority = priority; + } + @NonNull + private String contextGroup; + @NonNull + private String defaultGroup; + @NonNull + private String sharedGroup; + @NonNull + private String confidentialGroup; + @NonNull + private String publicGroup; + @NonNull + private Integer priority; + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/GeoServerDescriptor.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/GeoServerDescriptor.java new file mode 100644 index 0000000..ee50500 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/GeoServerDescriptor.java @@ -0,0 +1,47 @@ +package org.gcube.spatial.data.sdi.model.service; + +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.gcube.spatial.data.sdi.model.credentials.Credentials; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@NoArgsConstructor +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class GeoServerDescriptor extends GeoServiceDescriptor { + + + + public GeoServerDescriptor(Version version, String baseEndpoint, List accessibleCredentials, + String confidentialWorkspace, String contextVisibilityWorkspace, String sharedWorkspace, + String publicWorkspace) { + super(version, baseEndpoint, accessibleCredentials); + this.confidentialWorkspace = confidentialWorkspace; + this.contextVisibilityWorkspace = contextVisibilityWorkspace; + this.sharedWorkspace = sharedWorkspace; + this.publicWorkspace = publicWorkspace; + } + @NonNull + private String confidentialWorkspace; + @NonNull + private String contextVisibilityWorkspace; + @NonNull + private String sharedWorkspace; + @NonNull + private String publicWorkspace; + @NonNull + private Long hostedLayersCount; + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/GeoServiceDescriptor.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/GeoServiceDescriptor.java new file mode 100644 index 0000000..9851f00 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/GeoServiceDescriptor.java @@ -0,0 +1,39 @@ +package org.gcube.spatial.data.sdi.model.service; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.gcube.spatial.data.sdi.model.credentials.Credentials; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@NoArgsConstructor +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class GeoServiceDescriptor { + + public GeoServiceDescriptor(Version version, String baseEndpoint, List accessibleCredentials) { + super(); + this.version = version; + this.baseEndpoint = baseEndpoint; + this.accessibleCredentials = accessibleCredentials; + } + @NonNull + private Version version; + @NonNull + private String baseEndpoint; + @NonNull + private List accessibleCredentials=new ArrayList(); + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/ThreddsDescriptor.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/ThreddsDescriptor.java new file mode 100644 index 0000000..14c496b --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/ThreddsDescriptor.java @@ -0,0 +1,32 @@ +package org.gcube.spatial.data.sdi.model.service; + +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.gcube.spatial.data.sdi.model.credentials.Credentials; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@ToString +@Getter +@Setter +@NoArgsConstructor +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class ThreddsDescriptor extends GeoServiceDescriptor{ + + + public ThreddsDescriptor(Version version, String baseEndpoint, List accessibleCredentials) { + super(version, baseEndpoint, accessibleCredentials); + // TODO Auto-generated constructor stub + } + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/Version.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/Version.java new file mode 100644 index 0000000..7b542bc --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/model/service/Version.java @@ -0,0 +1,29 @@ +package org.gcube.spatial.data.sdi.model.service; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@Data +@RequiredArgsConstructor +@NoArgsConstructor +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class Version { + + @NonNull + private Short major; + @NonNull + private Short minor; + @NonNull + private Short build; + + public Version(Integer maj,Integer min, Integer build){ + this(maj.shortValue(),min.shortValue(),build.shortValue()); + } +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/GeoNetwork.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/GeoNetwork.java new file mode 100644 index 0000000..104a054 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/GeoNetwork.java @@ -0,0 +1,119 @@ +package org.gcube.spatial.data.sdi.rest; + +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; + +import org.gcube.smartgears.annotations.ManagedBy; +import org.gcube.spatial.data.sdi.NetUtils; +import org.gcube.spatial.data.sdi.SDIServiceManager; +import org.gcube.spatial.data.sdi.engine.RoleManager; +import org.gcube.spatial.data.sdi.engine.SDIManager; +import org.gcube.spatial.data.sdi.model.ServiceConstants; +import org.gcube.spatial.data.sdi.model.credentials.Credentials; +import org.gcube.spatial.data.sdi.model.service.GeoNetworkDescriptor; +import org.gcube.spatial.data.sdi.model.services.GeoNetworkServiceDefinition; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition.Type; + +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.jaxrs.annotation.JacksonFeatures; + +import lombok.extern.slf4j.Slf4j; + +@Path(ServiceConstants.GeoNetwork.INTERFACE) +@Slf4j +@ManagedBy(SDIServiceManager.class) +public class GeoNetwork { + + private final static String HOST_PATH_PARAM="host"; + + + + + @Inject + private SDIManager sdi; + @Inject + private RoleManager roleManager; + + + + @GET + @Path("configuration/{"+HOST_PATH_PARAM+"}") + @Produces(MediaType.APPLICATION_JSON) + @JacksonFeatures(serializationEnable = { SerializationFeature.INDENT_OUTPUT }) + public GeoNetworkDescriptor getInstanceConfiguration(@PathParam(HOST_PATH_PARAM) String host){ + try{ + log.trace("Serving credentials for host {} ",host); + host=NetUtils.getHost(host); + + return sdi.getGeoNetworkManager().getDescriptorByHostname(host); + + }catch(WebApplicationException e){ + log.warn("Unable to serve request",e); + throw e; + }catch(Exception e){ + log.warn("Unable to serve request",e); + throw new WebApplicationException("Unable to serve request", e); + } + } + + + @GET + @Path("credentials/{"+HOST_PATH_PARAM+"}") + @Produces(MediaType.APPLICATION_JSON) + @JacksonFeatures(serializationEnable = { SerializationFeature.INDENT_OUTPUT }) + public Credentials getInstanceCredentials(@PathParam(HOST_PATH_PARAM) String host){ + try{ + log.trace("Serving credentials for host {} ",host); + host=NetUtils.getHost(host); + return roleManager.getMostAccessible(sdi.getGeoNetworkManager().getDescriptorByHostname(host).getAccessibleCredentials(), false); +// return .get(0); + }catch(WebApplicationException e){ + log.warn("Unable to serve request",e); + throw e; + }catch(Exception e){ + log.warn("Unable to serve request",e); + throw new WebApplicationException("Unable to serve request", e); + } + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_XML) + public String register(GeoNetworkServiceDefinition toRegister) { + try { + return sdi.registerService(toRegister); + }catch(WebApplicationException e) { + log.warn("Unable to serve request",e); + throw e; + }catch(Exception e) { + log.warn("Unable to serve request",e); + throw new WebApplicationException("Unable to serve request",e); + } + } + + @POST + @Path("import/{"+HOST_PATH_PARAM+"}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_XML) + public String importFromScope(@QueryParam("sourceToken") String sourceToken,@PathParam(HOST_PATH_PARAM) String host) { + try { + return sdi.importService(sourceToken, host, Type.GEONETWORK); + }catch(WebApplicationException e) { + log.warn("Unable to serve request",e); + throw e; + }catch(Exception e) { + log.warn("Unable to serve request",e); + throw new WebApplicationException("Unable to serve request",e); + } + } + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/GeoServer.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/GeoServer.java new file mode 100644 index 0000000..ede0db7 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/GeoServer.java @@ -0,0 +1,112 @@ +package org.gcube.spatial.data.sdi.rest; + +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; + +import org.gcube.smartgears.annotations.ManagedBy; +import org.gcube.spatial.data.sdi.NetUtils; +import org.gcube.spatial.data.sdi.SDIServiceManager; +import org.gcube.spatial.data.sdi.engine.SDIManager; +import org.gcube.spatial.data.sdi.model.ServiceConstants; +import org.gcube.spatial.data.sdi.model.credentials.Credentials; +import org.gcube.spatial.data.sdi.model.service.GeoServerDescriptor; +import org.gcube.spatial.data.sdi.model.services.GeoServerDefinition; +import org.gcube.spatial.data.sdi.model.services.ServiceDefinition.Type; + +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.jaxrs.annotation.JacksonFeatures; + +import lombok.extern.slf4j.Slf4j; + +@Path(ServiceConstants.GeoServer.INTERFACE) +@Slf4j +@ManagedBy(SDIServiceManager.class) +public class GeoServer { + + private final static String HOST_PATH_PARAM="host"; + + + @Inject + private SDIManager sdi; + + @GET + @Path("configuration/{"+HOST_PATH_PARAM+"}") + @Produces(MediaType.APPLICATION_JSON) + @JacksonFeatures(serializationEnable = { SerializationFeature.INDENT_OUTPUT }) + public GeoServerDescriptor getInstanceConfiguration(@PathParam(HOST_PATH_PARAM) String host){ + try{ + log.trace("Serving credentials for host {} ",host); + host=NetUtils.getHost(host); + + return sdi.getGeoServerManager().getDescriptorByHostname(host); + + }catch(WebApplicationException e){ + log.warn("Unable to serve request",e); + throw e; + }catch(Exception e){ + log.warn("Unable to serve request",e); + throw new WebApplicationException("Unable to serve request", e); + } + } + + + @GET + @Path("credentials/{"+HOST_PATH_PARAM+"}") + @Produces(MediaType.APPLICATION_JSON) + @JacksonFeatures(serializationEnable = { SerializationFeature.INDENT_OUTPUT }) + public Credentials getInstanceCredentials(@PathParam(HOST_PATH_PARAM) String host){ + try{ + log.trace("Serving credentials for host {} ",host); + host=NetUtils.getHost(host); + return sdi.getGeoServerManager().getDescriptorByHostname(host).getAccessibleCredentials().get(0); + }catch(WebApplicationException e){ + log.warn("Unable to serve request",e); + throw e; + }catch(Exception e){ + log.warn("Unable to serve request",e); + throw new WebApplicationException("Unable to serve request", e); + } + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_XML) + public String register(GeoServerDefinition toRegister) { + try { + return sdi.registerService(toRegister); + }catch(WebApplicationException e) { + log.warn("Unable to serve request",e); + throw e; + }catch(Exception e) { + log.warn("Unable to serve request",e); + throw new WebApplicationException("Unable to serve request",e); + } + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Path("import/{"+HOST_PATH_PARAM+"}") + @Produces(MediaType.APPLICATION_XML) + public String importFromScope(@QueryParam("sourceToken") String sourceToken,@PathParam(HOST_PATH_PARAM) String host) { + try { + return sdi.importService(sourceToken, host, Type.GEOSERVER); + }catch(WebApplicationException e) { + log.warn("Unable to serve request",e); + throw e; + }catch(Exception e) { + log.warn("Unable to serve request",e); + throw new WebApplicationException("Unable to serve request",e); + } + } + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/Metadata.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/Metadata.java new file mode 100644 index 0000000..3b59363 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/Metadata.java @@ -0,0 +1,169 @@ +package org.gcube.spatial.data.sdi.rest; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response.Status; + +import org.gcube.smartgears.annotations.ManagedBy; +import org.gcube.spatial.data.sdi.SDIServiceManager; +import org.gcube.spatial.data.sdi.engine.GeoNetworkManager; +import org.gcube.spatial.data.sdi.engine.TemplateManager; +import org.gcube.spatial.data.sdi.engine.TemporaryPersistence; +import org.gcube.spatial.data.sdi.engine.impl.faults.gn.MetadataNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.gn.extension.GeoNetworkClient; +import org.gcube.spatial.data.sdi.engine.impl.gn.extension.GeoNetworkUtils; +import org.gcube.spatial.data.sdi.engine.impl.metadata.MetadataHandler; +import org.gcube.spatial.data.sdi.engine.impl.metadata.TemplateApplicationReport; +import org.gcube.spatial.data.sdi.model.ServiceConstants; +import org.gcube.spatial.data.sdi.model.metadata.MetadataReport; +import org.gcube.spatial.data.sdi.model.metadata.TemplateCollection; +import org.gcube.spatial.data.sdi.model.metadata.TemplateDescriptor; +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocation; +import org.gcube.spatial.data.sdi.model.service.GeoNetworkDescriptor; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.glassfish.jersey.media.multipart.FormDataParam; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Path(ServiceConstants.Metadata.INTERFACE) +@ManagedBy(SDIServiceManager.class) +public class Metadata { + + @Inject + private TemplateManager templateManager; + @Inject + private GeoNetworkManager geonetworkManager; + @Inject + private TemporaryPersistence persistence; + + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + public String uploadMetadata(@FormDataParam(ServiceConstants.Metadata.UPLOADED_FILE_PARAMETER) InputStream uploadedMeta, + @FormDataParam(ServiceConstants.Metadata.UPLOADED_FILE_PARAMETER) FormDataContentDisposition uploadedMetaDetails){ + try { + log.debug("Receiving metadata upload... size {} ",uploadedMetaDetails.getSize()); + return persistence.store(uploadedMeta); + } catch (IOException e) { + log.error("Unable to store file. ",e); + throw new WebApplicationException("Unable to store file locally. Cause : "+e.getMessage(),Status.INTERNAL_SERVER_ERROR); + } + } + + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/{uploadedId}") + public MetadataReport applyTemplates(Collection templateInvocations, @PathParam("uploadedId") String uploadedId){ + log.debug("Checking uploaded id {} ",uploadedId); + File uploaded=null; + try { + uploaded=persistence.getById(uploadedId); + } catch (FileNotFoundException e) { + log.debug("Unable to ge uploaded with ID {}. Cause : ",uploadedId,e); + throw new WebApplicationException("Invalid upload id "+uploadedId); + } + MetadataReport toReturn=new MetadataReport(); + Set metadataEnrichments=new HashSet<>(templateInvocations); + + if(metadataEnrichments!=null && !metadataEnrichments.isEmpty()){ + try{ + log.debug("Applying invocations..."); + TemplateApplicationReport report=templateManager.applyMetadataTemplates(uploaded, metadataEnrichments); + toReturn.setAppliedTemplates(report.getAppliedTemplates()); + persistence.update(uploadedId, new FileInputStream(new File(report.getGeneratedFilePath()))); + }catch(Throwable e){ + log.debug("Unable to apply templates. ",e); + throw new WebApplicationException("Unable to apply templates. Cause : "+e.getMessage(),Status.INTERNAL_SERVER_ERROR); + } + } + return toReturn; + } + + + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/publish/{uploadedId}/{gnCategory}") + public MetadataReport publishMetadata(@QueryParam(ServiceConstants.Metadata.VALIDATE_PARAMETER) @DefaultValue("true") Boolean validate, + @QueryParam(ServiceConstants.Metadata.PUBLIC_PARAMETER) @DefaultValue("false") Boolean makePublic, + @QueryParam(ServiceConstants.Metadata.STYLESHEET_PARAMETER) @DefaultValue("_none_") String styleSheet, + @PathParam("gnCategory") String category, @PathParam("uploadedId") String uploadedId){ + try{ + log.debug("PUBLISHING METADATA. UPLOADED ID {} ",uploadedId); + MetadataReport toReturn=new MetadataReport(); + File toPublish=persistence.getById(uploadedId); + log.debug("Publishing metadata.. "); + + GeoNetworkDescriptor desc=geonetworkManager.getSuggestedInstances().get(0); + GeoNetworkClient client=geonetworkManager.getClient(desc); + + String uuid=new MetadataHandler(toPublish).getUUID(); + long id=0; + try { + id=client.insertMetadata(category,styleSheet,validate,Integer.parseInt(desc.getDefaultGroup()),makePublic,toPublish); + }catch(Exception e) { + log.info("INSERT OPERATION FAILED. TRYING TO UPDATE."); + try{ + id=GeoNetworkUtils.getIDByUUID(client, uuid); + client.updateMeta(id, toPublish); + }catch(MetadataNotFoundException e1) { + throw new RuntimeException("Insert Operation failed with unexpected reason (Metadata with uuid "+uuid+" has not been found).",e); + } + } + + + toReturn.setPublishedID(id); + toReturn.setPublishedUUID(uuid); + return toReturn; + } catch (FileNotFoundException e) { + log.warn("Unable to get uploaded with ID {}. Cause : ",uploadedId,e); + throw new WebApplicationException("Invalid upload id "+uploadedId); + }catch(Throwable e ){ + log.warn("Unexpected error while publishing {} . Cause : ",uploadedId,e); + throw new WebApplicationException("Unabel to publish metadata. Cause "+e.getMessage(),Status.INTERNAL_SERVER_ERROR); + } + } + + + + @GET + @Path("/list") + @Produces(MediaType.APPLICATION_JSON) + public Collection getList(){ + try{ + log.debug("Received LIST method"); + TemplateCollection coll= templateManager.getAvailableMetadataTemplates(); + log.debug("Gonna respond with {} ",coll); + return coll.getAvailableTemplates(); + }catch(Throwable e ){ + log.warn("Unexpected error while getting templates",e); + throw new WebApplicationException("Unabel to publish metadata. Cause "+e.getMessage(),Status.INTERNAL_SERVER_ERROR); + } + } + + + + + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/SDI.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/SDI.java new file mode 100644 index 0000000..f76b935 --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/SDI.java @@ -0,0 +1,78 @@ +package org.gcube.spatial.data.sdi.rest; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; + +import org.gcube.smartgears.annotations.ManagedBy; +import org.gcube.spatia.data.model.profiles.ApplicationProfile; +import org.gcube.spatial.data.sdi.SDIServiceManager; +import org.gcube.spatial.data.sdi.engine.SDIManager; +import org.gcube.spatial.data.sdi.model.ScopeConfiguration; +import org.gcube.spatial.data.sdi.model.ServiceConstants; +import org.gcube.spatial.data.sdi.model.health.HealthReport; + +import lombok.extern.slf4j.Slf4j; + +@Path(ServiceConstants.INTERFACE) +//@Api(value=ServiceConstants.INTERFACE) +@ManagedBy(SDIServiceManager.class) +@Slf4j +public class SDI { + + @Inject + private SDIManager sdiManager; + + + @GET + @Produces(MediaType.APPLICATION_JSON) + public ScopeConfiguration getConfiguration(){ + try { + ScopeConfiguration config=sdiManager.getContextConfiguration(); + log.debug("Served Configuration"); + return config; + }catch(Throwable t) { + log.error("Unable to serve get configuration"); + throw new WebApplicationException("Unable to get configuration. Contact administrator.",t); + } + + } + + + @GET + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + @Path("status") + public HealthReport getReport() { + try{ + return sdiManager.getHealthReport(); + }catch(Throwable t) { + log.error("Unabel to get Health Report ",t); + throw new WebApplicationException("Unable to check Health. Contact administrator.",t); + } + } + + public static final String SERVICE_CLASS_PARAM="service_class"; + public static final String SERVICE_NAME_PARAM="service_name"; + + @GET + @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) + @Path("profile/{"+SERVICE_CLASS_PARAM+"}/{"+SERVICE_NAME_PARAM+"}") + public ApplicationProfile getProfile(@PathParam(SERVICE_CLASS_PARAM) String serviceClass, + @PathParam(SERVICE_NAME_PARAM) String serviceName) { + try { + log.debug("Looking for Application Profile [SC :{} SN : {}]",serviceClass,serviceName); + throw new RuntimeException("Feature not yet available"); + }catch(WebApplicationException e){ + log.warn("Unable to serve request",e); + throw e; + }catch(Throwable e){ + log.warn("Unable to serve request",e); + throw new WebApplicationException("Unable to serve request", e); + } + } + +} diff --git a/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/Thredds.java b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/Thredds.java new file mode 100644 index 0000000..b7dc56e --- /dev/null +++ b/sdi-service/src/main/java/org/gcube/spatial/data/sdi/rest/Thredds.java @@ -0,0 +1,77 @@ +package org.gcube.spatial.data.sdi.rest; + +import javax.inject.Inject; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; + +import org.gcube.data.transfer.model.plugins.thredds.ThreddsCatalog; +import org.gcube.smartgears.annotations.ManagedBy; +import org.gcube.spatial.data.sdi.SDIServiceManager; +import org.gcube.spatial.data.sdi.engine.ThreddsManager; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; + +import lombok.extern.slf4j.Slf4j; + +@Path("Thredds") +//@Api(value="Thredds") +@Slf4j +@ManagedBy(SDIServiceManager.class) +public class Thredds { + + private static class Constants{ + public static final String AUTHORITY_PARAMETER="authority"; + public static final String PATH_PARAMETER="path"; + public static final String FOLDER_PARAMETER="folder"; + public static final String BASE_NAME_PARAMETER="name"; + } + + + + @Inject + private ThreddsManager threddsManager; + + + @PUT + @Produces(MediaType.APPLICATION_JSON) + public ThreddsCatalog registerCatalog(@QueryParam(Constants.AUTHORITY_PARAMETER) @DefaultValue("www.d4science.org") String authority, + @QueryParam(Constants.BASE_NAME_PARAMETER) String baseName, + @QueryParam(Constants.PATH_PARAMETER) String path, + @QueryParam(Constants.FOLDER_PARAMETER) String folder) { + try { + String scopeName=ScopeUtils.getCurrentScopeName(); + + log.info("Received register catalog request under scope {} ",scopeName); + + if(baseName==null) { + log.debug("Base name not provided, using VRE {} ",scopeName); + baseName=scopeName+"_VRE"; + } + + if(folder==null) { + log.debug("Folder not provided, using base name {} ",baseName); + folder=baseName+"_folder"; + } + + if(path==null) { + log.debug("Path not provided, using baseName {} ",baseName); + path=baseName; + } + + + String datasetScanName=(baseName+" Catalog").replace("_", " "); + String datasetScanId=baseName+"_in_"+folder; + String catalogReference=(baseName).replaceAll("_", " "); + + return threddsManager.createCatalogFromTemplate(authority,path,datasetScanId,datasetScanName,folder,catalogReference); + }catch(Throwable t) { + log.warn("Unable to create catalog",t); + throw new WebApplicationException("Unable to serve request", t); + } + } + +} diff --git a/sdi-service/src/main/resources/META-INF/beans.xml b/sdi-service/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..14bded4 --- /dev/null +++ b/sdi-service/src/main/resources/META-INF/beans.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/sdi-service/src/main/resources/META-INF/services/org.gcube.smartgears.handlers.application.ApplicationHandler b/sdi-service/src/main/resources/META-INF/services/org.gcube.smartgears.handlers.application.ApplicationHandler new file mode 100644 index 0000000..e14fcea --- /dev/null +++ b/sdi-service/src/main/resources/META-INF/services/org.gcube.smartgears.handlers.application.ApplicationHandler @@ -0,0 +1 @@ +org.gcube.spatial.data.sdi.SDIServiceLifecycleManager \ No newline at end of file diff --git a/sdi-service/src/main/webapp/WEB-INF/config.properties b/sdi-service/src/main/webapp/WEB-INF/config.properties new file mode 100644 index 0000000..587fc0b --- /dev/null +++ b/sdi-service/src/main/webapp/WEB-INF/config.properties @@ -0,0 +1,73 @@ +#GEONETWORK +gn.cache.TTL=120000 +gn.se.category=Gis +gn.se.platform=geonetwork +gn.se.priority=priority +gn.se.endpointName=geonetwork +gn.se.suffixes=suffixes +gn.se.assigned.scope.prefix=scope +gn.se.scope.user.prefix=scopeUser +gn.se.scope.password.prefix=scopePwd +gn.se.ckan.user.prefix=ckanUser +gn.se.ckan.password.prefix=ckanPwd +gn.se.manager.user.prefix=mngUser +gn.se.manager.password.prefix=mngPwd +gn.se.default.group.prefix=default +gn.se.shared.group.prefix=public +gn.se.confidential.group.prefix=confidential +gn.se.context.group.prefix=private + +gn.groups.all=1 +gn.groups.max_length=32 + + +gn.ge.serviceClass=SDI +gn.ge.serviceName=GeoNetwork + +gn.update.timeout=60000 +gn.update.wait=500 + +gn.contact.mail=fabio.sinibaldi@isti.cnr.it +gn.password.length=10 + + +gn.mandatorySG=true + + +#GEOSERVER +gs.cache.TTL=120000 + +gs.cache.hostedLayers.TTL=60000 +gs.cache.styles.TTL=60000 +gs.cache.workspaces.TTL=600000 +gs.cache.datastores.TTL=600000 + + +gs.se.category=Gis +gs.se.platform=GeoServer +gs.ge.serviceClass=SDI +gs.ge.serviceName=GeoServer +gs.se.endpointName=geoserver + + +gs.mandatorySG=false + + +#THREDDS +th.cache.TTL=120000 +th.se.category=Gis +th.se.platform=Thredds +th.ge.serviceClass=SDI +th.ge.serviceName=Thredds +th.se.endpointName=Thredds + +th.se.remoteManagement.access=Remote_Management +th.mandatorySG=true + + +#Metadata +tpl.folder=WEB-INF/xmlTemplates +#TEMP +temp.ttl=120000 +#IS +is.registration.timeout=60000 \ No newline at end of file diff --git a/sdi-service/src/main/webapp/WEB-INF/gcube-app.xml b/sdi-service/src/main/webapp/WEB-INF/gcube-app.xml new file mode 100644 index 0000000..d034671 --- /dev/null +++ b/sdi-service/src/main/webapp/WEB-INF/gcube-app.xml @@ -0,0 +1,8 @@ + + sdi-service + SDI + 1.1.0-SNAPSHOT + REST Interface towards SDI facilities + + + diff --git a/sdi-service/src/main/webapp/WEB-INF/gcube-handlers.xml b/sdi-service/src/main/webapp/WEB-INF/gcube-handlers.xml new file mode 100644 index 0000000..f44ec08 --- /dev/null +++ b/sdi-service/src/main/webapp/WEB-INF/gcube-handlers.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/sdi-service/src/main/webapp/WEB-INF/web.xml b/sdi-service/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..18809d2 --- /dev/null +++ b/sdi-service/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,25 @@ + + + org.gcube.spatial.data.sdi.SDIService + org.glassfish.jersey.servlet.ServletContainer + + + javax.ws.rs.Application + org.gcube.spatial.data.sdi.SDIService + + + jersey.config.server.provider.classnames + org.glassfish.jersey.media.multipart.MultiPartFeature + + + + jersey.config.xml.formatOutput + true + + 1 + + + org.gcube.spatial.data.sdi.SDIService + /gcube/service/* + + \ No newline at end of file diff --git a/sdi-service/src/main/webapp/WEB-INF/xmlTemplates/ThreddsOnlineResources.ftlx b/sdi-service/src/main/webapp/WEB-INF/xmlTemplates/ThreddsOnlineResources.ftlx new file mode 100644 index 0000000..26ae87e --- /dev/null +++ b/sdi-service/src/main/webapp/WEB-INF/xmlTemplates/ThreddsOnlineResources.ftlx @@ -0,0 +1,220 @@ + + + + + + OPeNDAP + + + 2.0.0 + + + + + + + NetCDFSubSet + + + 1.0.0 + + + + + + + WCS + + + 1.0.0 + + + + + + + WMS + + + 1.1.0 + + + + + + + HTTPServer + + + 1.1.0 + + + + + + + NCML + + + 1.0.0 + + + + + + + UDDC + + + 1.0.0 + + + + + + + <#if catalog??> + <#assign cataloguedPath=catalog+"/"+filename> + <#else> + <#assign cataloguedPath=filename> + + + <#assign layername=filename?keep_before_last(".")> + + + + + http://${hostname}/thredds/dodsC/${cataloguedPath} + + + WWW:LINK-1.0-http--link + + + ${layername} : OPeNDAP + + + GIS data (OPenNDAP) + + + + + + + + http://${hostname}/thredds/ncss/${cataloguedPath} + + + WWW:LINK-1.0-http--link + + + ${layername} : NetCDF Subset + + + GIS data (NetCDF Subset) + + + + + + + + http://${hostname}/thredds/wcs/${cataloguedPath}?service=wcs&version=1.0.0&request=GetCoverage&coverage=${layername}&CRS=EPSG:4326&format=geotiff + + + OGC:WCS-1.0.0-http-get-coverage + + + ${layername} : WCS + + + GIS data (WCS) + + + + + + + + http://${hostname}/thredds/wms/${cataloguedPath} + + + OGC:WMS-1.3.0-http-get-map + + + ${layername} : WMS + + + GIS data (WMS) + + + + + + + + http://${hostname}/thredds/fileServer/${cataloguedPath} + + + WWW:LINK-1.0-http--link + + + ${layername} : HTTP + + + GIS data (HTTP FileServer) + + + + + + + + http://${hostname}/thredds/ncml/${cataloguedPath} + + + WWW:LINK-1.0-http--link + + + ${layername} : NCML + + + GIS metadata (NCML Format) + + + + + + + + + http://${hostname}/thredds/uddc/${cataloguedPath} + + + WWW:LINK-1.0-http--link + + + ${layername} : UDDC + + + GIS metadata quality (UDDC) + + + + + + + + ${gisViewerLink} + + + WWW:LINK-1.0-http--link + + + GIS Viewer link + + + + + + + \ No newline at end of file diff --git a/sdi-service/src/main/webapp/WEB-INF/xmlTemplates/thredds_catalog.ftlx b/sdi-service/src/main/webapp/WEB-INF/xmlTemplates/thredds_catalog.ftlx new file mode 100644 index 0000000..c97a8ab --- /dev/null +++ b/sdi-service/src/main/webapp/WEB-INF/xmlTemplates/thredds_catalog.ftlx @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + ${AuthorityURL} + + + + + all + + + + + + + + + + + \ No newline at end of file diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/ConfigurationTest.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/ConfigurationTest.java new file mode 100644 index 0000000..39bf51f --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/ConfigurationTest.java @@ -0,0 +1,29 @@ +package org.gcube.spatial.data.sdi.test; + +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Paths; + +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.impl.GISManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.GeoNetworkManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.RoleManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.SDIManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.ThreddsManagerImpl; +import org.gcube.spatial.data.sdi.test.factories.ThreddsManagerFactory; + +public class ConfigurationTest { + + public static void main(String[] args) throws MalformedURLException { + TokenSetter.set("/d4science.research-infrastructures.eu/gCubeApps/BiodiversityLab"); + +// TokenSetter.set("/gcube/devNext/NextNext"); + LocalConfiguration.init(Paths.get("src/main/webapp/WEB-INF/config.properties").toUri().toURL()); + + SDIManagerImpl sdi=new SDIManagerImpl(new GeoNetworkManagerImpl(new RoleManagerImpl()), new ThreddsManagerFactory().provide(), new GISManagerImpl()); + + System.out.println(sdi.getContextConfiguration()); + System.out.println(sdi.getContextConfiguration().getGeonetworkConfiguration().get(0).getAccessibleCredentials()); + } + +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/MainTest.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/MainTest.java new file mode 100644 index 0000000..2489687 --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/MainTest.java @@ -0,0 +1,139 @@ +package org.gcube.spatial.data.sdi.test; + +import java.net.MalformedURLException; +import java.nio.file.Paths; +import java.util.List; + +import javax.ws.rs.core.Application; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; + +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.SDIService; +import org.gcube.spatial.data.sdi.engine.GISManager; +import org.gcube.spatial.data.sdi.engine.GeoNetworkManager; +import org.gcube.spatial.data.sdi.engine.RoleManager; +import org.gcube.spatial.data.sdi.engine.SDIManager; +import org.gcube.spatial.data.sdi.engine.TemplateManager; +import org.gcube.spatial.data.sdi.engine.TemporaryPersistence; +import org.gcube.spatial.data.sdi.engine.ThreddsManager; +import org.gcube.spatial.data.sdi.model.ServiceConstants; +import org.gcube.spatial.data.sdi.model.metadata.TemplateDescriptor; +import org.gcube.spatial.data.sdi.test.factories.GISManagerFactory; +import org.gcube.spatial.data.sdi.test.factories.GeoNetworkManagerFactory; +import org.gcube.spatial.data.sdi.test.factories.MetadataTemplateManagerFactory; +import org.gcube.spatial.data.sdi.test.factories.RoleManagerFactory; +import org.gcube.spatial.data.sdi.test.factories.SDIManagerFactory; +import org.gcube.spatial.data.sdi.test.factories.TemporaryPersistenceFactory; +import org.gcube.spatial.data.sdi.test.factories.ThreddsManagerFactory; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.BeforeClass; +import org.junit.Test; + +public class MainTest extends JerseyTest{ + + @BeforeClass + public static void init() throws MalformedURLException { + LocalConfiguration.init(Paths.get("src/main/webapp/WEB-INF/config.properties").toUri().toURL()); + } + + + public static class MyBinder extends AbstractBinder{ + + public MyBinder() { + super(); + // TODO Auto-generated constructor stub + } + + @Override + protected void configure() { + bindFactory(TemporaryPersistenceFactory.class).to(TemporaryPersistence.class); + bindFactory(RoleManagerFactory.class).to(RoleManager.class); + bindFactory(SDIManagerFactory.class).to(SDIManager.class); + bindFactory(ThreddsManagerFactory.class).to(ThreddsManager.class); + bindFactory(GeoNetworkManagerFactory.class).to(GeoNetworkManager.class); + bindFactory(GISManagerFactory.class).to(GISManager.class); + bindFactory(MetadataTemplateManagerFactory.class).to(TemplateManager.class); + } + } + + @Override + protected Application configure() { + System.out.println("Configuration for "+ServiceConstants.APPLICATION); + + ResourceConfig config= new ResourceConfig(SDIService.class); + config.register(new MyBinder()); +// config.register(io.swagger.jaxrs.listing.ApiListingResource.class); +// config.register(io.swagger.jaxrs.listing.SwaggerSerializers.class); +// +// //SWAGGER +// BeanConfig beanConfig = new BeanConfig(); +// beanConfig.setVersion("1.0.0"); +// beanConfig.setSchemes(new String[]{"http","https"}); +// beanConfig.setHost("localhost:9998"); +// beanConfig.setBasePath("gcube/service"); +// String packageName=GeoNetwork.class.getPackage().getName(); +// System.out.println("PACKAGE : "+packageName); +// beanConfig.setResourcePackage(packageName); +// beanConfig.setScan(true); +// System.out.println(beanConfig.getSwagger()); +// +// + + //Multipart +// config.packages("org.glassfish.jersey.media.multipart"); + config.packages("org.gcube.spatial.data"); + config.register(MultiPartFeature.class); + return config; + } + + +// @Test +// public void getConfiguration(){ +// System.out.println(target(Constants.GEONETWORK_INTERFACE). +// path(Constants.GEONETWORK_CONFIGURATION_PATH). +// request(MediaType.APPLICATION_JSON_TYPE).get(String.class)); +// System.out.println(target(Constants.GEONETWORK_INTERFACE). +// path(Constants.GEONETWORK_CONFIGURATION_PATH). +// getUri()); +// } + + + + @Test + public void getConfiguration(){ + System.out.println(target(ServiceConstants.INTERFACE).request(MediaType.APPLICATION_JSON_TYPE).get(String.class)); + } +// + @Test + public void getGeoServer(){ + System.out.println(target(ServiceConstants.GeoServer.INTERFACE).path("configuration/geoserver1.dev.d4science.org").request(MediaType.APPLICATION_JSON_TYPE).get(String.class)); + } + + @Test + public void testGetTemplateList(){ + List result=target(ServiceConstants.Metadata.INTERFACE). + path(ServiceConstants.Metadata.LIST_METHOD). + request(MediaType.APPLICATION_JSON_TYPE).get(). + readEntity(new GenericType>() {}); + System.out.println(result); + } + + @Test + public void testHealthReport() { + System.out.println(target(ServiceConstants.INTERFACE).path("status").request(MediaType.APPLICATION_JSON_TYPE).get(String.class)); + System.out.println(target(ServiceConstants.INTERFACE).path("status").request(MediaType.APPLICATION_XML_TYPE).get(String.class)); + } + + +// +// @Test +// public void getSwagger(){ +// String path="gcube/service/swagger.json"; +// System.out.println(target(path).getUri()); +// System.out.println(target(path).request(MediaType.APPLICATION_JSON_TYPE).get(String.class)); +// } +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/MetadataApplicationTest.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/MetadataApplicationTest.java new file mode 100644 index 0000000..70537f1 --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/MetadataApplicationTest.java @@ -0,0 +1,40 @@ +package org.gcube.spatial.data.sdi.test; + +import java.io.IOException; +import java.nio.file.Paths; + +import javax.xml.transform.TransformerException; + +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.TemplateManager; +import org.gcube.spatial.data.sdi.engine.impl.metadata.MetadataTemplateManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.metadata.TemplateApplicationReport; +import org.gcube.spatial.data.sdi.model.metadata.TemplateInvocationBuilder; +import org.junit.Test; + +public class MetadataApplicationTest { + + @Test + public void apply() throws IOException, TransformerException{ + TokenSetter.set("/gcube/devNext/NextNext"); + MetadataTemplateManagerImpl manager=new MetadataTemplateManagerImpl(); +// LocalConfiguration.init(Paths.get("src/main/webapp/WEB-INF/config.properties").toUri().toURL()) +// .setTemplateConfigurationObject(Paths.get("src/main/webapp/WEB-INF/metadataTemplates").toFile()); + + manager.init(Paths.get("src/main/webapp/WEB-INF/xmlTemplates").toFile()); + + + System.out.println(manager.getAvailableMetadataTemplates()); + + + TemplateInvocationBuilder builder=new TemplateInvocationBuilder(); + builder.threddsOnlineResources("localhost", "someFileName.sc", "newCatalog"); + TemplateApplicationReport report=manager.applyMetadataTemplates(Paths.get("src/test/resources/xml/toEnrichMetadata.xml").toFile(), builder.get()); + System.out.println(report); + + + + } + + +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/NetTests.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/NetTests.java new file mode 100644 index 0000000..fd5c021 --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/NetTests.java @@ -0,0 +1,14 @@ +package org.gcube.spatial.data.sdi.test; + +import java.io.IOException; + +import org.gcube.spatial.data.sdi.NetUtils; + +public class NetTests { + + public static void main(String[] args) throws IOException { + TokenSetter.set("/gcube/devNext"); + NetUtils.makeAuthorizedCall("thredds-d-d4s.d4science.org", "thredds/admin/debug?catalogs/reinit", "tds", "trythat"); + } + +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/RegisterServiceTest.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/RegisterServiceTest.java new file mode 100644 index 0000000..7a275ec --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/RegisterServiceTest.java @@ -0,0 +1,80 @@ +package org.gcube.spatial.data.sdi.test; + +import java.net.MalformedURLException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; + +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.impl.GISManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.GeoNetworkManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.RoleManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.SDIManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.ThreddsManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.faults.ServiceRegistrationException; +import org.gcube.spatial.data.sdi.model.ParameterType; +import org.gcube.spatial.data.sdi.model.services.GeoNetworkServiceDefinition; +import org.gcube.spatial.data.sdi.test.factories.ThreddsManagerFactory; + +import ch.qos.logback.core.util.SystemInfo; + +public class RegisterServiceTest { + + + public static void main(String[] args) throws MalformedURLException, ServiceRegistrationException { + TokenSetter.set("/d4science.research-infrastructures.eu/gCubeApps/AlienAndInvasiveSpecies"); + + LocalConfiguration.init(Paths.get("src/main/webapp/WEB-INF/config.properties").toUri().toURL()); + + SDIManagerImpl sdi=new SDIManagerImpl(new GeoNetworkManagerImpl(new RoleManagerImpl()), new ThreddsManagerFactory().provide(), new GISManagerImpl()); + + + System.out.println(sdi.registerService(getGNDefinition())); + + + + + } + + + private static GeoNetworkServiceDefinition getGNDefinition() { + GeoNetworkServiceDefinition def=new GeoNetworkServiceDefinition(); + def.setAdminPassword("gCube@Gn321_sdi"); + def.setDescription("GeoNetwork v3 Serving Demo VREs"); + def.setHostname("geonetwork-spatialdata.d4science.org"); + def.setMajorVersion((short)3); + def.setMinorVersion((short)2); + def.setReleaseVersion((short)1); + def.setName("GeoNetwork 3 Alien"); + def.setPriority(10); + ParameterType[] params=new ParameterType[] { + new ParameterType("suffixes",""), + //devNext Manually configured +// new ParameterType("scope1","devNext"), +// new ParameterType("scopeUser1","devNext_context"), +// new ParameterType("scopePwd1","123456"), +// new ParameterType("ckanUser1","devNext_ckan"), +// new ParameterType("scopePwd1","987456"), +// new ParameterType("mngUser1","devNext_manager"), +// new ParameterType("mngPwd1","741852"), +// new ParameterType("default1","1"), +// new ParameterType("public1","1"), +// new ParameterType("confidential1","1"), +// new ParameterType("private1","1"), + //NextNext +// new ParameterType("scope2","NextNext"), +// new ParameterType("scopeUser2","nextNext_context"), +// new ParameterType("scopePwd2","456789"), +// new ParameterType("ckanUser2","nextNext_ckan"), +// new ParameterType("scopePwd2","123789"), +// new ParameterType("mngUser2","nextNext_manager"), +// new ParameterType("mngPwd2","963852"), +// new ParameterType("default2","1"), +// new ParameterType("public2","1"), +// new ParameterType("confidential2","1"), +// new ParameterType("private2","1"), + }; + def.setProperties(new ArrayList(Arrays.asList(params))); + return def; + } +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/RoleManagerTests.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/RoleManagerTests.java new file mode 100644 index 0000000..b1bd7da --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/RoleManagerTests.java @@ -0,0 +1,33 @@ +package org.gcube.spatial.data.sdi.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.gcube.spatial.data.sdi.engine.RoleManager; +import org.gcube.spatial.data.sdi.engine.impl.RoleManagerImpl; +import org.gcube.spatial.data.sdi.model.credentials.AccessType; +import org.gcube.spatial.data.sdi.model.credentials.Credentials; + +public class RoleManagerTests { + + + public static void main(String[] args) { + RoleManager manager=new RoleManagerImpl(); + + List toFilter=new ArrayList(); + toFilter.add(new Credentials("admin","adminpwd",AccessType.ADMIN)); + toFilter.add(new Credentials("manager","managerpwd",AccessType.CONTEXT_MANAGER)); + toFilter.add(new Credentials("user","userpwd",AccessType.CONTEXT_USER)); + toFilter.add(new Credentials("ckan","ckanPWD",AccessType.CKAN)); + + +// System.out.println(manager.getMostAccessible(toFilter, false)); +// System.out.println(manager.getMostAccessible(toFilter, true)); +// + System.out.println(manager.getMostAccessible(Arrays.asList( + new Credentials("user","pwd",AccessType.CONTEXT_USER), + new Credentials("ckan","ckanPWD",AccessType.CKAN)), true)); + } + +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TestCommon.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TestCommon.java new file mode 100644 index 0000000..6e54dee --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TestCommon.java @@ -0,0 +1,7 @@ +package org.gcube.spatial.data.sdi.test; + +public class TestCommon { + + public static final String TEST_SCOPE="/gcube/devNext"; + +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TestCreateCatalog.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TestCreateCatalog.java new file mode 100644 index 0000000..66ddef2 --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TestCreateCatalog.java @@ -0,0 +1,85 @@ +package org.gcube.spatial.data.sdi.test; + +import java.net.MalformedURLException; +import java.nio.file.Paths; + +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.ThreddsManager; +import org.gcube.spatial.data.sdi.engine.impl.ThreddsManagerImpl; +import org.gcube.spatial.data.sdi.test.factories.ThreddsManagerFactory; + +public class TestCreateCatalog { + + public static void main(String[] args) throws MalformedURLException { +// TokenSetter.set("/d4science.research-infrastructures.eu/gCubeApps/BiodiversityLab"); + + + TokenSetter.set("/gcube/devNext"); + + + LocalConfiguration.init(Paths.get("src/main/webapp/WEB-INF/config.properties").toUri().toURL()); + + ThreddsManager mng=new ThreddsManagerFactory().provide(); + + /* + * "PUT /sdi-service/gcube/service/Thredds? + * name=Thredds+Root+Catalog& + * path=public/netcdf/syncfolderfrancesco& + * folder=public/netcdf/syncfolderfrancesco HTTP/1.1" 1057 Jersey/2.13 (HttpUrlConnection 1.8.0_131) + */ + + + String baseName="ThreddsRootCatalog"; + String authority="www.d4science.org"; + String path="public/netcdf/syncfolderfrancesco"; + String folder="public/netcdf/Anothersyncfolderfrancesco"; + + + /* + * + @QueryParam(Constants.AUTHORITY_PARAMETER) @DefaultValue("www.d4science.org") String authority, + @QueryParam(Constants.BASE_NAME_PARAMETER) String baseName, + @QueryParam(Constants.PATH_PARAMETER) String path, + @QueryParam(Constants.FOLDER_PARAMETER) String folder) + + + + try { + String scopeName=ScopeUtils.getCurrentScopeName(); + + log.info("Received register catalog request under scope {} ",scopeName); + + if(baseName==null) { + log.debug("Base name not provided, using VRE {} ",scopeName); + baseName=scopeName+"_VRE"; + } + + if(folder==null) { + log.debug("Folder not provided, using base name {} ",baseName); + folder=baseName+"_folder"; + } + + if(path==null) { + log.debug("Path not provided, using baseName {} ",baseName); + path=baseName; + } + + */ + String datasetScanName=(baseName+" Catalog").replace("_", " "); + String datasetScanId=baseName+"_in_"+folder; + String catalogReference=(baseName).replaceAll("_", " "); + + + + + + try { + + mng.createCatalogFromTemplate(authority,path,datasetScanId,datasetScanName,folder,catalogReference); + }catch(Exception e) { + e.printStackTrace(); + } + + } + +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TestIS.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TestIS.java new file mode 100644 index 0000000..8af76cd --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TestIS.java @@ -0,0 +1,32 @@ +package org.gcube.spatial.data.sdi.test; + +import java.net.MalformedURLException; +import java.nio.file.Paths; + +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.spatial.data.sdi.LocalConfiguration; +import org.gcube.spatial.data.sdi.engine.impl.is.ISUtils; +import org.gcube.spatial.data.sdi.utils.ScopeUtils; + +public class TestIS { + + public static void main(String[] args) throws MalformedURLException { + TokenSetter.set("/gcube/devNext/NextNext"); + LocalConfiguration.init(Paths.get("src/main/webapp/WEB-INF/config.properties").toUri().toURL()); + ServiceEndpoint e=ISUtils.querySEById("8e1962e9-05a7-40d4-a56f-574431f4c907"); + + e.profile().description(e.profile().description()+"_modified"); + + System.out.println("Identity : "+ISUtils.marshal(e).equals(ISUtils.marshal(e))); + + + System.out.println(ISUtils.updateAndWait(e)); + + System.out.println("PARENTS"); + System.out.println(ScopeUtils.getParentScope("/gcube")); + System.out.println(ScopeUtils.getParentScope("/gcube/devNext")); + System.out.println(ScopeUtils.getParentScope("/gcube/devNext/NextNext")); + + } + +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TokenSetter.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TokenSetter.java new file mode 100644 index 0000000..1f8181d --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/TokenSetter.java @@ -0,0 +1,38 @@ +package org.gcube.spatial.data.sdi.test; + +import java.util.Properties; + +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; +import org.gcube.common.scope.api.ScopeProvider; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TokenSetter { + + +private static Properties props=new Properties(); + + static{ + try { + props.load(TokenSetter.class.getResourceAsStream("/tokens.properties")); + } catch (Exception e) { + throw new RuntimeException("YOU NEED TO SET TOKEN FILE IN CONFIGURATION"); + } + } + + + public static void set(String scope){ + try{ + if(!props.containsKey(scope)) throw new RuntimeException("No token found for scope : "+scope); + SecurityTokenProvider.instance.set(props.getProperty(scope)); + }catch(Throwable e){ + log.warn("Unable to set token for scope "+scope,e); + } + ScopeProvider.instance.set(scope); + } + + + + +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/GISManagerFactory.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/GISManagerFactory.java new file mode 100644 index 0000000..281897e --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/GISManagerFactory.java @@ -0,0 +1,48 @@ +package org.gcube.spatial.data.sdi.test.factories; + +import org.gcube.spatial.data.sdi.engine.GISManager; +import org.gcube.spatial.data.sdi.engine.impl.GISManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.cluster.AbstractCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.GeoServerCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.GeoServerController; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.service.GeoServerDescriptor; +import org.gcube.spatial.data.sdi.test.TestCommon; +import org.gcube.spatial.data.sdi.test.TokenSetter; +import org.glassfish.hk2.api.Factory; + +public class GISManagerFactory implements Factory{ + + private GISManager manager; + + public GISManagerFactory() { + manager=new GISManagerImpl(){ + + @Override + protected ISModule getRetriever() { + TokenSetter.set(TestCommon.TEST_SCOPE); + return super.getRetriever(); + } + + @Override + protected AbstractCluster getCluster() { + TokenSetter.set(TestCommon.TEST_SCOPE); + return super.getCluster(); + } + + }; + } + + + @Override + public void dispose(GISManager arg0) { + // TODO Auto-generated method stub + + } + + @Override + public GISManager provide() { + return manager; + } +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/GeoNetworkManagerFactory.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/GeoNetworkManagerFactory.java new file mode 100644 index 0000000..eb0a8bc --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/GeoNetworkManagerFactory.java @@ -0,0 +1,43 @@ +package org.gcube.spatial.data.sdi.test.factories; + +import org.gcube.spatial.data.sdi.engine.GeoNetworkManager; +import org.gcube.spatial.data.sdi.engine.impl.GeoNetworkManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.cluster.AbstractCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.GeoNetworkController; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.service.GeoNetworkDescriptor; +import org.gcube.spatial.data.sdi.test.TestCommon; +import org.gcube.spatial.data.sdi.test.TokenSetter; +import org.glassfish.hk2.api.Factory; + +public class GeoNetworkManagerFactory implements Factory{ + + private GeoNetworkManager manager; + + public GeoNetworkManagerFactory() { + manager=new GeoNetworkManagerImpl(new RoleManagerFactory().provide()){ + @Override + protected ISModule getRetriever() { + TokenSetter.set(TestCommon.TEST_SCOPE); + return super.getRetriever(); + } + + @Override + protected AbstractCluster getCluster() { + TokenSetter.set(TestCommon.TEST_SCOPE); + return super.getCluster(); + } + }; + } + + @Override + public void dispose(GeoNetworkManager arg0) { + // TODO Auto-generated method stub + + } + + @Override + public GeoNetworkManager provide() { + return manager; + } +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/MetadataTemplateManagerFactory.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/MetadataTemplateManagerFactory.java new file mode 100644 index 0000000..b368743 --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/MetadataTemplateManagerFactory.java @@ -0,0 +1,26 @@ +package org.gcube.spatial.data.sdi.test.factories; + +import java.nio.file.Paths; + +import org.gcube.spatial.data.sdi.engine.TemplateManager; +import org.gcube.spatial.data.sdi.engine.impl.metadata.MetadataTemplateManagerImpl; +import org.glassfish.hk2.api.Factory; + +public class MetadataTemplateManagerFactory implements Factory{ + + public MetadataTemplateManagerFactory() { + // TODO Auto-generated constructor stub + } + + @Override + public void dispose(TemplateManager arg0) { + // TODO Auto-generated method stub + + } + @Override + public TemplateManager provide() { + MetadataTemplateManagerImpl manager=new MetadataTemplateManagerImpl(); + manager.init(Paths.get("src/main/webapp/WEB-INF/xmlTemplates").toFile()); + return manager; + } +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/RoleManagerFactory.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/RoleManagerFactory.java new file mode 100644 index 0000000..422e89c --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/RoleManagerFactory.java @@ -0,0 +1,19 @@ +package org.gcube.spatial.data.sdi.test.factories; + +import org.gcube.spatial.data.sdi.engine.RoleManager; +import org.gcube.spatial.data.sdi.engine.impl.RoleManagerImpl; +import org.glassfish.hk2.api.Factory; + +public class RoleManagerFactory implements Factory{ + + @Override + public RoleManager provide() { + return new RoleManagerImpl(); + } + + @Override + public void dispose(RoleManager arg0) { + // TODO Auto-generated method stub + + } +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/SDIManagerFactory.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/SDIManagerFactory.java new file mode 100644 index 0000000..6b9759c --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/SDIManagerFactory.java @@ -0,0 +1,41 @@ +package org.gcube.spatial.data.sdi.test.factories; + +import org.gcube.spatial.data.sdi.engine.SDIManager; +import org.gcube.spatial.data.sdi.engine.impl.SDIManagerImpl; +import org.gcube.spatial.data.sdi.model.ScopeConfiguration; +import org.gcube.spatial.data.sdi.model.health.HealthReport; +import org.gcube.spatial.data.sdi.test.TestCommon; +import org.gcube.spatial.data.sdi.test.TokenSetter; +import org.glassfish.hk2.api.Factory; + +public class SDIManagerFactory implements Factory{ + + SDIManager manager=null; + + + public SDIManagerFactory() { + manager=new SDIManagerImpl(new GeoNetworkManagerFactory().provide(),new ThreddsManagerFactory().provide(),new GISManagerFactory().provide()){ + @Override + public ScopeConfiguration getContextConfiguration() { + TokenSetter.set(TestCommon.TEST_SCOPE); + return super.getContextConfiguration(); + } + @Override + public HealthReport getHealthReport() { + TokenSetter.set(TestCommon.TEST_SCOPE); + return super.getHealthReport(); + } + }; + } + + @Override + public void dispose(SDIManager arg0) { + // TODO Auto-generated method stub + + } + + @Override + public SDIManager provide() { + return manager; + } +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/TemporaryPersistenceFactory.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/TemporaryPersistenceFactory.java new file mode 100644 index 0000000..934c3e4 --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/TemporaryPersistenceFactory.java @@ -0,0 +1,24 @@ +package org.gcube.spatial.data.sdi.test.factories; + +import org.gcube.spatial.data.sdi.engine.TemporaryPersistence; +import org.gcube.spatial.data.sdi.engine.impl.TemporaryPersistenceImpl; +import org.glassfish.hk2.api.Factory; + +public class TemporaryPersistenceFactory implements Factory{ + + + @Override + public void dispose(TemporaryPersistence arg0) { + arg0.shutdown(); + } + + @Override + public TemporaryPersistence provide() { + TemporaryPersistenceImpl temp=new TemporaryPersistenceImpl(); + + temp.init(); + + return temp; + } + +} diff --git a/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/ThreddsManagerFactory.java b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/ThreddsManagerFactory.java new file mode 100644 index 0000000..417ba6b --- /dev/null +++ b/sdi-service/src/test/java/org/gcube/spatial/data/sdi/test/factories/ThreddsManagerFactory.java @@ -0,0 +1,47 @@ +package org.gcube.spatial.data.sdi.test.factories; + +import org.gcube.spatial.data.sdi.engine.ThreddsManager; +import org.gcube.spatial.data.sdi.engine.impl.ThreddsManagerImpl; +import org.gcube.spatial.data.sdi.engine.impl.cluster.AbstractCluster; +import org.gcube.spatial.data.sdi.engine.impl.cluster.ThreddsController; +import org.gcube.spatial.data.sdi.engine.impl.faults.ConfigurationNotFoundException; +import org.gcube.spatial.data.sdi.engine.impl.is.ISModule; +import org.gcube.spatial.data.sdi.model.health.ServiceHealthReport; +import org.gcube.spatial.data.sdi.model.service.ThreddsDescriptor; +import org.gcube.spatial.data.sdi.test.TestCommon; +import org.gcube.spatial.data.sdi.test.TokenSetter; +import org.glassfish.hk2.api.Factory; + +public class ThreddsManagerFactory implements Factory{ + + private ThreddsManager manager; + + + public ThreddsManagerFactory() { + manager=new ThreddsManagerImpl(new MetadataTemplateManagerFactory().provide()){ + @Override + protected AbstractCluster getCluster() { + TokenSetter.set(TestCommon.TEST_SCOPE); + return super.getCluster(); + } + + @Override + protected ISModule getRetriever() { + TokenSetter.set(TestCommon.TEST_SCOPE); + return super.getRetriever(); + } + }; + } + + + @Override + public ThreddsManager provide() { + return manager; + } + + @Override + public void dispose(ThreddsManager arg0) { + // TODO Auto-generated method stub + + } +} diff --git a/sdi-service/src/test/resources/logback.xml b/sdi-service/src/test/resources/logback.xml new file mode 100644 index 0000000..b70dd26 --- /dev/null +++ b/sdi-service/src/test/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file diff --git a/sdi-service/src/test/resources/xml/toEnrichMetadata.xml b/sdi-service/src/test/resources/xml/toEnrichMetadata.xml new file mode 100644 index 0000000..ba81844 --- /dev/null +++ b/sdi-service/src/test/resources/xml/toEnrichMetadata.xml @@ -0,0 +1,446 @@ + + + + + English + + + UTF-8 + + + Dataset + + + + + fabio.sinibaldi + + + iMarine Consortium + + + Author + + + + + + + iMarine Consortium + + + iMarine.eu + + + + + + + info@i-marine.eu + + + + + + + http://www.i-marine.eu + + + WWW:LINK-1.0-http--link + + + i-Marine project website + + + + + + + Distributor + + + + + + + iMarine Consortium Technical Support + + + iMarine.eu + + + + + + + support@i-marine.eu + + + + + + + http://www.i-marine.eu + + + WWW:LINK-1.0-http--link + + + i-Marine project website + + + + + + + Resource provider + + + + + 2013-06-19T04:41:20.762+02:00 + + + + + Geometry only + + + + + Surface + + + 362 + + + + + + + + + + + Latimeria chalumnae + + + + + 2012-12-21T00:47:59.555+01:00 + + + Creation + + + + + Map digital + + + + + This Latimeria chalumnae Species Distribution Map has been generated with the AquaMaps methodology by exploiting the technology and the computational resources provided by iMarine. In particular, this map has been produced using the HSPEC 2050 Native Range dataset, generated using AquaMaps NativeRange2050 algorithm. + + + The aim of this Species Distribution map is to provide its users with a model-based map displaying prediction of species distributions based on occurrence records. + + + This layer has been produced by iMarine (www.i-marine.eu). iMarine (283644) is funded by the European Commission under Framework Programme 7 + + + Kaschner, K., J. S. Ready, E. Agbayani, J. Rius, K. Kesner-Reyes, P. D. Eastwood, A. B. South, S. O. Kullander, T. Rees, C. H. Close, R. Watson, D. Pauly, and R. Froese. 2008 AquaMaps: Predicted range maps for aquatic species. World wide web electronic publication, www.aquamaps.org, Version 10/2008. + + + + + As needed + + + + + + + http://node49.p.d4science.research-infrastructures.eu:9003/83/Animalia/Chordata/Sarcopterygii/Coelacanthiformes/Latimeriidae/Fis-30189/Earth.jpg + + + + + + + Coelacanth + + + Theme + + + + + FISHBASE + + + + + 2013-06-18T18:06:55.662+02:00 + + + Creation + + + + + + + FISHBASE + + + IFM-GEOMAR + + + + + + + http://www.fishbase.org/search.php + + + FISHBASE website + + + + + + + Point of contact + + + + + FishBase is a global species database of fish species (specifically finfish). + + + + + + + + + Latimeria chalumnae + + + Theme + + + + + OBIS + + + + + 2013-06-18T18:06:55.662+02:00 + + + Creation + + + + + + + OBIS + + + UNESCO + + + + + + + http://www.iobis.org + + + OBIS website + + + + + + + Point of contact + + + + + Intergovernmental Oceanographic Commission (IOC) of UNESCO. The Ocean Biogeographic Information System. Web. http://www.iobis.org. (Consulted on DATE) + + + + + + + + + Ecological niche modelling + + + AquaMaps + + + SpeciesDistribution + + + iMarine + + + Theme + + + + + General + + + + + 2013-06-19T04:41:20.762+02:00 + + + Creation + + + + + + + + + + + 0.5 + + + + + English + + + biota + + + + + + + true + + + -180.0 + + + 180.0 + + + -90.0 + + + 90.0 + + + + + + + + + + + + + + Dataset + + + + + + + Kaschner, K., J. S. Ready, E. Agbayani, J. Rius, K. Kesner-Reyes, P. D. Eastwood, A. B. South, S. O. Kullander, T. Rees, C. H. Close, R. Watson, D. Pauly, and R. Froese. 2008 AquaMaps: Predicted range maps for aquatic species. World wide web electronic publication, www.aquamaps.org, Version 10/2008. + + + + + AquaMaps Ecological Niche Modelling + + + + + + + + + HSPEC 2050 Native Range + + + + + 2011-10-05T00:39:17.101+02:00 + + + Creation + + + + + + + hspec2011_10_04_21_00_23_274 + + + + + + + + + + + true + + + -180.0 + + + 180.0 + + + -90.0 + + + 90.0 + + + + + + + + + + + + + + + CC-BY-SA + + + License + + + License + + + +