Commit 043bb37c authored by Nico Mack's avatar Nico Mack

Implemented WebService Connector

Added Authentication to WebService calls
Update to latest version of Jersey
parent 8c911517
......@@ -6,3 +6,8 @@ DRIVER_CLASS_ELEMENT=driverClass
USER_NAME_ELEMENT=username
PASSWORD_ELEMENT=password
AUTO_COMMIT_ELEMENT=autoCommit
TOKEN_ELEMENT=token
MEDIA_ELEMENT=media
TYPE_ATTRIBUTE=type
BEARER_VALUE=bearer
\ No newline at end of file
......@@ -114,7 +114,7 @@
<dependency>
<groupId>lu.list.itis.dkd.tui</groupId>
<artifactId>tulip</artifactId>
<version>2.7.0</version>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>maven2.dk.ange</groupId>
......@@ -146,7 +146,7 @@
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.26</version>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
......@@ -156,7 +156,7 @@
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.26</version>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.github.lucarosellini.rJava</groupId>
......@@ -179,6 +179,11 @@
<scope>runtime</scope>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.security</groupId>
<artifactId>oauth2-client</artifactId>
<version>${jersey.version}</version>
</dependency>
</dependencies>
<repositories>
......@@ -218,5 +223,6 @@
<properties>
<postgres.version>42.2.6</postgres.version>
<mysql.version>8.0.17</mysql.version>
<jersey.version>2.30.1</jersey.version>
</properties>
</project>
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2019. All rights reserved. If you wish
* to use this code for any purpose, please contact the author(s).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.cps.system.connector;
import lu.list.itis.dkd.tui.cps.system.connector.builder.BaseWebServiceConnectorBuilder;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.client.oauth2.OAuth2ClientSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Feature;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 1.8.0
* @version 1.0.0
*/
// ***************************************************************************
// * Class Definition *
// ***************************************************************************
public class WebServiceConnector extends Connector<Client> {
protected String url;
protected String token;
protected String tokenType;
private Client client;
// ***************************************************************************
// * Constants
// ***************************************************************************
private static Pattern TRAILING_SLASH_PATTERN = Pattern.compile("^(.*?)\\/$", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
private static Pattern LEADING_SLASH_PATTERN = Pattern.compile("^\\/(.*?)$", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
private static final Logger LOGGER = LoggerFactory.getLogger(WebServiceConnector.class.getSimpleName());
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
public WebServiceConnector(BaseWebServiceConnectorBuilder<?> builder) {
super(builder);
Matcher trailingSlash = TRAILING_SLASH_PATTERN.matcher(builder.url);
this.url = (trailingSlash.matches()) ? trailingSlash.group(1) : builder.url;
this.token = builder.token;
this.tokenType = builder.tokenType;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
// ***************************************************************************
// ---------------------------------------------------------------------------
private Client setupConnection() {
client = ClientBuilder.newClient();
try {
if (StringUtils.isNoneBlank(this.token)) {
Feature authentication = OAuth2ClientSupport.feature(this.token);
client = client.register(authentication);
}
} catch (IllegalArgumentException exception) {
LOGGER.error("The specified URI {} is not valid!", this.url); //$NON-NLS-1$
}
return client;
}
// ---------------------------------------------------------------------------
private void tearDownConnection() {
client.close();
client = null;
LOGGER.info("Connection to service at {} closed!", this.url); //$NON-NLS-1$
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// *Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
@Override
public void connect() {
this.setupConnection();
super.connect();
}
// ---------------------------------------------------------------------------
@Override
public Client getConnection() {
return this.client;
}
// ---------------------------------------------------------------------------
@Override
public void disconnect() {
super.disconnect();
this.tearDownConnection();
}
// ---------------------------------------------------------------------------
public String buildTargetUri(String requestUrl) {
StringBuilder targetUri = new StringBuilder(this.url);
Matcher leadingSlash = LEADING_SLASH_PATTERN.matcher(requestUrl);
targetUri.append('/').append((leadingSlash.matches()) ? leadingSlash.group(1) : requestUrl);
return targetUri.toString();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2019. All rights reserved. If you wish
* to use this code for any purpose, please contact the author(s).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.cps.system.connector.builder;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapCallback;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapContext;
import lu.list.itis.dkd.tui.bootstrapping.BootstrappingUtils;
import lu.list.itis.dkd.tui.cps.system.connector.WebServiceConnector;
import lu.list.itis.dkd.tui.cps.system.connector.utility.ConnectorBundle;
import lu.list.itis.dkd.tui.exception.BuildException;
import org.jdom2.Element;
/**
* @author mack
* @since [major].[minor]
* @version [major].[minor].[micro]
*/
public abstract class BaseWebServiceConnectorBuilder<B extends BaseWebServiceConnectorBuilder<B>> extends BaseConnectorBuilder<B> {
public String url;
public String token;
public String tokenType;
// ***************************************************************************
// * Constants *
// ***************************************************************************
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param rootElement
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public BaseWebServiceConnectorBuilder(Element rootElement) throws BuildException {
super(rootElement);
this.buildFromBootstrap(rootElement, null, null);
}
// ---------------------------------------------------------------------------
/**
* @param rootElement
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public BaseWebServiceConnectorBuilder(Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
super(rootElement, context, callback);
this.buildFromBootstrap(rootElement, context, callback);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
// ***************************************************************************
// ---------------------------------------------------------------------------
private void buildFromBootstrap(@Nullable Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
this.url = BootstrappingUtils.getContentAsString(rootElement, ConnectorBundle.URL_ELEMENT, BootstrappingUtils.MANDATORY, null, context);
Element tokenElement = BootstrappingUtils.getChild(rootElement, ConnectorBundle.TOKEN_ELEMENT, BootstrappingUtils.OPTIONAL);
if (tokenElement != null) {
this.tokenType = BootstrappingUtils.getAttributeAsString(tokenElement, ConnectorBundle.TYPE_ATTRIBUTE, BootstrappingUtils.MANDATORY, null);
this.token = BootstrappingUtils.getContentAsString(tokenElement, null, BootstrappingUtils.MANDATORY, null, context);
}
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
@Override
public abstract WebServiceConnector build();
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2019. All rights reserved. If you wish
* to use this code for any purpose, please contact the author(s).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.cps.system.connector.builder;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapCallback;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapContext;
import lu.list.itis.dkd.tui.cps.system.connector.WebServiceConnector;
import lu.list.itis.dkd.tui.exception.BuildException;
import org.jdom2.Element;
/**
* @author mack
* @since [major].[minor]
* @version [major].[minor].[micro]
*/
// ***************************************************************************
// * Class Definition *
// ***************************************************************************
public class WebServiceConnectorBuilder extends BaseWebServiceConnectorBuilder<WebServiceConnectorBuilder> {
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param rootElement
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public WebServiceConnectorBuilder(Element rootElement) throws BuildException {
super(rootElement);
}
// ---------------------------------------------------------------------------
/**
* @param rootElement
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public WebServiceConnectorBuilder(Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException {
super(rootElement, context, callback);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// *Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
public WebServiceConnector build() {
return new WebServiceConnector(this);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
......@@ -32,11 +32,17 @@ public class ConnectorBundle extends NLS {
public static String USER_NAME_ELEMENT;
public static String PASSWORD_ELEMENT;
public static String AUTO_COMMIT_ELEMENT;
public static String TOKEN_ELEMENT;
public static String MEDIA_ELEMENT;
public static String TYPE_ATTRIBUTE;
public static String BEARER_VALUE;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, ConnectorBundle.class);
}
private ConnectorBundle() {}
private ConnectorBundle() {
}
}
\ No newline at end of file
package lu.list.itis.dkd.tui.cps.system.executor;
import lu.list.itis.dkd.tui.cps.system.Declaration;
import lu.list.itis.dkd.tui.cps.system.connector.WebServiceConnector;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import com.google.common.base.Strings;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.client.ClientResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -17,7 +19,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.client.WebTarget;
......@@ -29,10 +30,9 @@ import javax.ws.rs.core.MediaType;
public class RESTfulWebServiceExecutor extends Executor {
Client client;
String serviceUrl;
WebTarget service;
String response;
private Map<String, Object> parameters;
// ***************************************************************************
......@@ -48,9 +48,7 @@ public class RESTfulWebServiceExecutor extends Executor {
private static final String OPTIONS = "OPTIONS"; //$NON-NLS-1$
private static final String HEAD = "HEAD"; //$NON-NLS-1$
private static final String PARAMETER_TEMPLATE = "Parameter -> {} = {}"; //$NON-NLS-1$
private static Pattern SCRIPT_PATTERN = Pattern.compile("^(POST|GET|PUT|DELETE|OPTIONS|HEAD)\\s+(.*?)$", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
private static Pattern SCRIPT_PATTERN = Pattern.compile("^(POST|GET|PUT|DELETE|OPTIONS|HEAD)\\s+(.*?)(\\s*(.*?))?$", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
// ---------------------------------------------------------------------------
// ***************************************************************************
......@@ -61,7 +59,6 @@ public class RESTfulWebServiceExecutor extends Executor {
public RESTfulWebServiceExecutor(Properties properties) {
super(properties);
client = ClientBuilder.newClient();
parameters = new ConcurrentHashMap<>();
}
......@@ -108,18 +105,42 @@ public class RESTfulWebServiceExecutor extends Executor {
this.executionErrors.reset();
Matcher callMatcher = SCRIPT_PATTERN.matcher(script);
if (callMatcher.matches()) {
WebServiceConnector webService = (WebServiceConnector) this.connector;
long elapsed = System.currentTimeMillis();
Client client = webService.getConnection();
String targetUri = webService.buildTargetUri(callMatcher.group(2));
MediaType responseType = (StringUtils.isNoneBlank(callMatcher.group(4))) ? MediaType.valueOf(callMatcher.group(4)) : MediaType.APPLICATION_JSON_TYPE;
try {
service = client.target(callMatcher.group(2));
service = client.target(targetUri);
Builder request = service.request();
switch (callMatcher.group(1)) {
String method = callMatcher.group(1);
switch (method) {
case POST:
request = request.accept(MediaType.APPLICATION_JSON_TYPE);
request = request.accept(responseType);
response = request.post(this.buildEntity(), String.class);
break;
case GET: // TODO Implement GET method
case PUT: // TODO Implement PUT method
case DELETE: // TODO Implement DELETE method
case OPTIONS: // TODO Implement OPTIONS method
case HEAD:
LOGGER.warn("{} not yet implemented!", method); //$NON-NLS-1$
break;
default:
LOGGER.warn("Unsupported {} method!", method); //$NON-NLS-1$
}
} catch (Exception exception) {
success = false;
ClientResponse status = client.target(serviceUrl).request().get(ClientResponse.class);
ClientResponse status = client.target(targetUri).request().get(ClientResponse.class);
LOGGER.error("Eval returned an error code: {}", status.getStatus()); //$NON-NLS-1$
}
elapsed = System.currentTimeMillis() - elapsed;
......@@ -140,7 +161,7 @@ public class RESTfulWebServiceExecutor extends Executor {
if (response != null) {
variable.setValueFromObject(response);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Result <- {} = {}", variable.getName(), response); //$NON-NLS-1$
LOGGER.info(RESULT_TEMPLATE_PLAIN, variable.getName(), response);
}
}
return variable;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment