diff options
47 files changed, 3288 insertions, 1442 deletions
@@ -347,7 +347,13 @@ <groupId>org.glassfish.jersey.inject</groupId> <artifactId>jersey-hk2</artifactId> </dependency> - </dependencies> + <dependency> + <groupId>pl.pragmatists</groupId> + <artifactId>JUnitParams</artifactId> + <version>1.1.0</version> + <scope>test</scope> + </dependency> + </dependencies> <reporting> <plugins> <plugin> @@ -381,7 +387,7 @@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jettyVersion>9.4.12.RC2</jettyVersion> <eelf.version>1.0.0</eelf.version> - <artifact.version>1.0.24-SNAPSHOT</artifact.version> + <artifact.version>1.0.25-SNAPSHOT</artifact.version> <!-- SONAR --> <jacoco.version>0.7.7.201606060606</jacoco.version> <sonar-jacoco-listeners.version>3.2</sonar-jacoco-listeners.version> diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/AafConnection.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafConnection.java index e22290a..934e541 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/aaf/AafConnection.java +++ b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafConnection.java @@ -37,8 +37,11 @@ import java.net.UnknownHostException; import java.net.ConnectException; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; import org.apache.commons.codec.binary.Base64; import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum; @@ -129,6 +132,10 @@ public class AafConnection extends BaseLoggingClass { uc.setRequestProperty( "Content-Length", Integer.toString( postData.length )); uc.setUseCaches(false); uc.setDoOutput(true); + + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + uc.setSSLSocketFactory(sc.getSocketFactory()); OutputStream os = null; @@ -296,6 +303,27 @@ public class AafConnection extends BaseLoggingClass { return rc; } + + private TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() + { + return null; + } + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) + { + //No need to implement. + } + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) + { + //No need to implement. + } + } + }; } diff --git a/src/main/java/org/onap/dmaap/dbcapi/client/DrProvConnection.java b/src/main/java/org/onap/dmaap/dbcapi/client/DrProvConnection.java index d603679..54fa84e 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/client/DrProvConnection.java +++ b/src/main/java/org/onap/dmaap/dbcapi/client/DrProvConnection.java @@ -49,6 +49,7 @@ public class DrProvConnection extends BaseLoggingClass { private String feedContentType; private String subContentType; private String unit_test; + private String provURI; private HttpsURLConnection uc; @@ -63,6 +64,7 @@ public class DrProvConnection extends BaseLoggingClass { behalfHeader = p.getProperty( "DR.onBehalfHeader", "X-DMAAP-DR-ON-BEHALF-OF"); feedContentType = p.getProperty( "DR.feedContentType", "application/vnd.dmaap-dr.feed"); subContentType = p.getProperty( "DR.subContentType", "application/vnd.dmaap-dr.subscription"); + provURI = p.getProperty( "DR.ProvisioningURI", "/internal/prov"); logger.info( "provURL=" + provURL + " provApi=" + provApi + " behalfHeader=" + behalfHeader + " feedContentType=" + feedContentType + " subContentType=" + subContentType ); unit_test = p.getProperty( "UnitTest", "No" ); @@ -97,6 +99,10 @@ public class DrProvConnection extends BaseLoggingClass { sub, nodep ); return makeConnection( provURL + uri ); } + public boolean makeDumpConnection() { + String url = provURL + provURI; + return makeConnection( url ); + } public boolean makeNodesConnection( String varName ) { String uri = String.format("/internal/api/%s", varName); @@ -923,5 +929,150 @@ public class DrProvConnection extends BaseLoggingClass { } + // add double-quotes around a value + // hope his is easier to read than in-line escaping... + private String dq( String v ) { + return ( "\"" + v + "\""); + } + private String dq( String k, String v) { + return( dq(k) + ":" + dq(v)); + } + private String dqc( String k, String v) { + return( dq(k) + ":" + dq(v) + ","); + } + + private String dumpSimulation() { + logger.info( "enter dumpSimulation()"); + String responseBody = + "{" + + dq("feeds") + ":[" + + "{" + dq( "suspend") + ":false," + + dq( "groupid") + ":0," + + dqc( "description", "Some description" ) + + dqc( "version", "m1.1") + + dq( "authorization") + ":" + + "{" + dq( "endpoint_addrs" ) + ":[]," + + dq( "classification", "unclassified") + + dq( "endpoint_ids") + ":[{" + + dqc( "password", "dradmin" ) + + dq( "id", "dradmin") + + "}]}" + + dq( "last_mod") + ":1553738110000," + + dq( "deleted") + ":false," + + dq( "feedid") + ":1," + + dqc( "name", "Default PM Feed") + + dq( "business_description") + ":\"\"," + + dqc( "publisher", "onap") + + dq( "links") + ":{" + + dqc( "subscribe", "https://dmaap-dr-prov/subscribe/1") + + dqc( "log", "https://dmaap-dr-prov/feedlog/1") + + dqc( "publish", "https://dmaap-dr-prov/publish/1") + + dq( "self", "https:/dmaap-dr-prov/feed/1") + + "}" + + dq( "created_date") + ":1553738110000 }" + + "]," + + dq( "groups") + ":[" + + "]," + + dq( "subscriptions") + ":[" + + "]," + + dq( "ingress") + ":[" + + "]," + + dq( "egress") + ":{" + + "}," + + dq( "routing") + ":[" + + "]," + + "}"; + return responseBody; + } + + public String doGetDump( ApiError err ) { + logger.info( "entry: doGetDump() " ); + + String responsemessage = null; + String responseBody = null; + + try { + + uc.setRequestMethod("GET"); + int rc = -1; + + + try { + uc.connect(); + + + } catch (ProtocolException pe) { + + // Rcvd error instead of 100-Continue + try { + // work around glitch in Java 1.7.0.21 and likely others + // without this, Java will connect multiple times to the server to run the same request + uc.setDoOutput(false); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + + rc = uc.getResponseCode(); + logger.info( "http response code:" + rc ); + responsemessage = uc.getResponseMessage(); + logger.info( "responsemessage=" + responsemessage ); + + + + if (responsemessage == null) { + + // work around for glitch in Java 1.7.0.21 and likely others + // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is + String h0 = uc.getHeaderField(0); + if (h0 != null) { + int i = h0.indexOf(' '); + int j = h0.indexOf(' ', i + 1); + if (i != -1 && j != -1) { + responsemessage = h0.substring(j + 1); + } + } + } + + err.setCode(rc); // may not really be an error, but we save rc + if (rc == 200 ) { + responseBody = bodyToString( uc.getInputStream() ); + logger.info( "responseBody=" + responseBody ); + } else { + err.setMessage(responsemessage); + } + + + } catch (ConnectException ce) { + if ( unit_test.equals( "Yes" ) ) { + err.setCode(200); + err.setMessage( "simulated response"); + logger.info( "artificial 200 response from doGetNodes because unit_test =" + unit_test ); + responseBody = dumpSimulation(); + + } else { + errorLogger.error( DmaapbcLogMessageEnum.HTTP_CONNECTION_EXCEPTION, provURL, ce.getMessage() ); + err.setCode( 500 ); + err.setMessage("Backend connection refused"); + logger.error(ce.getMessage(), ce); + } + } catch (Exception e) { + if ( unit_test.equals( "Yes" ) ) { + err.setCode(200); + err.setMessage( "simulated response"); + logger.info( "artificial 200 response from doGetNodes because unit_test =" + unit_test ); + responseBody = dumpSimulation(); + + } else { + logger.error("Unable to read response ", e.getMessage()); + } + } finally { + + if ( uc != null ) uc.disconnect(); + } + + return responseBody; + + } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/client/MrProvConnection.java b/src/main/java/org/onap/dmaap/dbcapi/client/MrProvConnection.java index 51bad4f..6e692fa 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/client/MrProvConnection.java +++ b/src/main/java/org/onap/dmaap/dbcapi/client/MrProvConnection.java @@ -36,131 +36,131 @@ import java.net.*; import java.util.Arrays; public class MrProvConnection extends BaseLoggingClass{ - - private String provURL; - - private HttpURLConnection uc; - - - private String topicMgrCred; - private boolean useAAF; - private String user; - private String encPwd; - - public MrProvConnection() { - String mechIdProperty = "aaf.TopicMgrUser"; - String pwdProperty = "aaf.TopicMgrPassword"; - DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig(); - user = p.getProperty( mechIdProperty, "noMechId@domain.netset.com" ); - encPwd = p.getProperty( pwdProperty, "notSet" ); - useAAF= "true".equalsIgnoreCase(p.getProperty("UseAAF", "false")); - topicMgrCred = getCred(); - - } - - private String getCred( ) { - - - String pwd = ""; - AafDecrypt decryptor = new AafDecrypt(); - pwd = decryptor.decrypt(encPwd); - return user + ":" + pwd; - } - - - public boolean makeTopicConnection( MR_Cluster cluster ) { - logger.info( "connect to cluster: " + cluster.getDcaeLocationName()); - - - provURL = cluster.getTopicProtocol() + "://" + cluster.getFqdn() + ":" + cluster.getTopicPort() + "/topics/create"; - - if ( cluster.getTopicProtocol().equals( "https" ) ) { - return makeSecureConnection( provURL ); - } - return makeConnection( provURL ); - } - - private boolean makeSecureConnection( String pURL ) { - logger.info( "makeConnection to " + pURL ); - - try { - URL u = new URL( pURL ); - uc = (HttpsURLConnection) u.openConnection(); - uc.setInstanceFollowRedirects(false); - logger.info( "open connect to " + pURL ); - return(true); - } catch( UnknownHostException uhe ){ - logger.error( "Caught UnknownHostException for " + pURL); - return(false); + + private String provURL; + + private HttpURLConnection uc; + + + private String topicMgrCred; + private boolean useAAF; + private String user; + private String encPwd; + + public MrProvConnection() { + String mechIdProperty = "aaf.TopicMgrUser"; + String pwdProperty = "aaf.TopicMgrPassword"; + DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig(); + user = p.getProperty( mechIdProperty, "noMechId@domain.netset.com" ); + encPwd = p.getProperty( pwdProperty, "notSet" ); + useAAF= "true".equalsIgnoreCase(p.getProperty("UseAAF", "false")); + topicMgrCred = getCred(); + + } + + private String getCred( ) { + + + String pwd = ""; + AafDecrypt decryptor = new AafDecrypt(); + pwd = decryptor.decrypt(encPwd); + return user + ":" + pwd; + } + + + public boolean makeTopicConnection( MR_Cluster cluster ) { + logger.info( "connect to cluster: " + cluster.getDcaeLocationName()); + + + provURL = cluster.getTopicProtocol() + "://" + cluster.getFqdn() + ":" + cluster.getTopicPort() + "/topics/create"; + + if ( cluster.getTopicProtocol().equals( "https" ) ) { + return makeSecureConnection( provURL ); + } + return makeConnection( provURL ); + } + + private boolean makeSecureConnection( String pURL ) { + logger.info( "makeConnection to " + pURL ); + + try { + URL u = new URL( pURL ); + uc = (HttpsURLConnection) u.openConnection(); + uc.setInstanceFollowRedirects(false); + logger.info( "open connect to " + pURL ); + return(true); + } catch( UnknownHostException uhe ){ + logger.error( "Caught UnknownHostException for " + pURL); + return(false); } catch (Exception e) { logger.error("Unexpected error during openConnection of " + pURL ); - e.printStackTrace(); + logger.error("Unexpected error during openConnection of ",e ); return(false); } - } - private boolean makeConnection( String pURL ) { - logger.info( "makeConnection to " + pURL ); - - try { - URL u = new URL( pURL ); - uc = (HttpURLConnection) u.openConnection(); - uc.setInstanceFollowRedirects(false); - logger.info( "open connect to " + pURL ); - return(true); - } catch( UnknownHostException uhe ){ - logger.error( "Caught UnknownHostException for " + pURL); - return(false); + } + private boolean makeConnection( String pURL ) { + logger.info( "makeConnection to " + pURL ); + + try { + URL u = new URL( pURL ); + uc = (HttpURLConnection) u.openConnection(); + uc.setInstanceFollowRedirects(false); + logger.info( "open connect to " + pURL ); + return(true); + } catch( UnknownHostException uhe ){ + logger.error( "Caught UnknownHostException for " + pURL); + return(false); } catch (Exception e) { logger.error("Unexpected error during openConnection of " + pURL ); - e.printStackTrace(); + logger.error("Unexpected error during openConnection of ",e ); return(false); } - } - - static String bodyToString( InputStream is ) { - StringBuilder sb = new StringBuilder(); - BufferedReader br = new BufferedReader( new InputStreamReader(is)); - String line; - try { - while ((line = br.readLine()) != null ) { - sb.append( line ); - } - } catch (IOException ex ) { - errorLogger.error( "IOexception:" + ex); - } - - return sb.toString(); - } - - public String doPostTopic( Topic postTopic, ApiError err ) { - String auth = "Basic " + Base64.encodeBase64String(topicMgrCred.getBytes()); - - - String responsemessage = null; - int rc = -1; - - - try { - byte[] postData = postTopic.getBytes(); - logger.info( "post fields=" + Arrays.toString(postData)); - - // when not using AAF, do not attempt Basic Authentication - if ( useAAF ) { - uc.setRequestProperty("Authorization", auth); - logger.info( "Authenticating with " + auth ); - } - uc.setRequestMethod("POST"); - uc.setRequestProperty("Content-Type", "application/json"); - uc.setRequestProperty( "charset", "utf-8"); - uc.setRequestProperty( "Content-Length", Integer.toString( postData.length )); - uc.setUseCaches(false); - uc.setDoOutput(true); - OutputStream os = null; - - - try { + } + + static String bodyToString( InputStream is ) { + StringBuilder sb = new StringBuilder(); + BufferedReader br = new BufferedReader( new InputStreamReader(is)); + String line; + try { + while ((line = br.readLine()) != null ) { + sb.append( line ); + } + } catch (IOException ex ) { + errorLogger.error( "IOexception:" + ex); + } + + return sb.toString(); + } + + public String doPostTopic( Topic postTopic, ApiError err ) { + String auth = "Basic " + Base64.encodeBase64String(topicMgrCred.getBytes()); + + + String responsemessage = null; + int rc = -1; + + + try { + byte[] postData = postTopic.getBytes(); + logger.info( "post fields=" + Arrays.toString(postData)); + + // when not using AAF, do not attempt Basic Authentication + if ( useAAF ) { + uc.setRequestProperty("Authorization", auth); + logger.info( "Authenticating with " + auth ); + } + uc.setRequestMethod("POST"); + uc.setRequestProperty("Content-Type", "application/json"); + uc.setRequestProperty( "charset", "utf-8"); + uc.setRequestProperty( "Content-Length", Integer.toString( postData.length )); + uc.setUseCaches(false); + uc.setDoOutput(true); + OutputStream os = null; + + + try { uc.connect(); os = uc.getOutputStream(); os.write( postData ); @@ -174,21 +174,21 @@ public class MrProvConnection extends BaseLoggingClass{ } catch (Exception e) { } } catch ( UnknownHostException uhe ) { - errorLogger.error( DmaapbcLogMessageEnum.UNKNOWN_HOST_EXCEPTION , "Unknown Host Exception" , provURL ); - err.setCode(500); - err.setMessage("Unknown Host Exception"); - err.setFields( uc.getURL().getHost()); - return new String( "500: " + uhe.getMessage()); + errorLogger.error( DmaapbcLogMessageEnum.UNKNOWN_HOST_EXCEPTION , "Unknown Host Exception" , provURL ); + err.setCode(500); + err.setMessage("Unknown Host Exception"); + err.setFields( uc.getURL().getHost()); + return new String( "500: " + uhe.getMessage()); }catch ( ConnectException ce ) { - errorLogger.error( DmaapbcLogMessageEnum.HTTP_CONNECTION_EXCEPTION, provURL, "HTTP Connection Exception" ); - err.setCode(500); - err.setMessage("HTTP Connection Exception"); - err.setFields( uc.getURL().getHost()); - return new String( "500: " + ce.getMessage()); + errorLogger.error( DmaapbcLogMessageEnum.HTTP_CONNECTION_EXCEPTION, provURL, "HTTP Connection Exception" ); + err.setCode(500); + err.setMessage("HTTP Connection Exception"); + err.setFields( uc.getURL().getHost()); + return new String( "500: " + ce.getMessage()); } - rc = uc.getResponseCode(); - logger.info( "http response code:" + rc ); - err.setCode(rc); + rc = uc.getResponseCode(); + logger.info( "http response code:" + rc ); + err.setCode(rc); responsemessage = uc.getResponseMessage(); logger.info( "responsemessage=" + responsemessage ); err.setMessage(responsemessage); @@ -207,29 +207,29 @@ public class MrProvConnection extends BaseLoggingClass{ } } if (rc >= 200 && rc < 300 ) { - String responseBody = null; - responseBody = bodyToString( uc.getInputStream() ); - logger.info( "responseBody=" + responseBody ); - return responseBody; + String responseBody = null; + responseBody = bodyToString( uc.getInputStream() ); + logger.info( "responseBody=" + responseBody ); + return responseBody; } - } catch (Exception e) { - errorLogger.error("Unable to read response " ); + } catch (Exception e) { + errorLogger.error("Unable to read response " ); } - finally { - try { - uc.disconnect(); - } catch ( Exception e ) { - errorLogger.error("Unable to disconnect"); - } - } - return new String( rc +": " + responsemessage ); + finally { + try { + uc.disconnect(); + } catch ( Exception e ) { + errorLogger.error("Unable to disconnect"); + } + } + return new String( rc +": " + responsemessage ); - } - + } + - + } diff --git a/src/main/java/org/onap/dmaap/dbcapi/database/DatabaseClass.java b/src/main/java/org/onap/dmaap/dbcapi/database/DatabaseClass.java index e2004bd..c853782 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/database/DatabaseClass.java +++ b/src/main/java/org/onap/dmaap/dbcapi/database/DatabaseClass.java @@ -32,201 +32,252 @@ import org.onap.dmaap.dbcapi.util.DmaapConfig; import org.onap.dmaap.dbcapi.util.Singleton; +public class DatabaseClass extends BaseLoggingClass { + private static Singleton<Dmaap> dmaap; + private static Map<String, DcaeLocation> dcaeLocations; + private static Map<String, DR_Node> dr_nodes; + private static Map<String, DR_Pub> dr_pubs; + private static Map<String, DR_Sub> dr_subs; + private static Map<String, MR_Client> mr_clients; + private static Map<String, MR_Cluster> mr_clusters; + private static Map<String, Feed> feeds; + private static Map<String, Topic> topics; + private static Map<String, MirrorMaker> mirrors; -public class DatabaseClass extends BaseLoggingClass { - - private static Singleton<Dmaap> dmaap; - private static Map<String, DcaeLocation> dcaeLocations; - private static Map<String, DR_Node> dr_nodes; - private static Map<String, DR_Pub> dr_pubs; - private static Map<String, DR_Sub> dr_subs; - private static Map<String, MR_Client> mr_clients; - private static Map<String, MR_Cluster> mr_clusters; - private static Map<String, Feed> feeds; - private static Map<String, Topic> topics; - private static Map<String, MirrorMaker> mirrors; - - private static long lastTime = 0L; - - - - private static class MirrorTopicsHandler implements DBFieldHandler.SqlOp { - public Object get(ResultSet rs, int index) throws Exception { - String val = rs.getString(index); - if (val == null) { - return(null); - } - List<String> rv = new ArrayList<>(); - for (String s: val.split(",")) { - rv.add(new String(s)); - } - return(rv); - } - public void set(PreparedStatement ps, int index, Object val) throws Exception { - if (val == null) { - ps.setString(index, null); - return; - } - @SuppressWarnings("unchecked") - List<String> xv = (List<String>)val; - StringBuilder sb = new StringBuilder(); - String sep = ""; - for (Object o: xv) { - String rv = (String)o; - sb.append(sep).append(DBFieldHandler.fesc(rv)); - sep = ","; - } - ps.setString(index, sb.toString()); - } - } - private static class TopicReplicationTypeHandler implements DBFieldHandler.SqlOp { - public Object get(ResultSet rs, int index) throws Exception { - int val = rs.getInt(index); - - return (ReplicationType.valueOf(val)); - } - public void set(PreparedStatement ps, int index, Object val) throws Exception { - if (val == null) { - ps.setInt(index, 0); - return; - } - @SuppressWarnings("unchecked") - ReplicationType rep = (ReplicationType) val; - ps.setInt(index, rep.getValue()); - } - } - public static Singleton<Dmaap> getDmaap() { - return dmaap; - } - - - - public static Map<String, DcaeLocation> getDcaeLocations() { - return dcaeLocations; - } - - public static Map<String, DR_Node> getDr_nodes() { - return dr_nodes; - } - - public static Map<String, DR_Sub> getDr_subs() { - return dr_subs; - } - public static Map<String, DR_Pub> getDr_pubs() { - return dr_pubs; - } - - public static Map<String, MR_Client> getMr_clients() { - return mr_clients; - } - - - public static Map<String, MR_Cluster> getMr_clusters() { - return mr_clusters; - } - - public static Map<String, Feed> getFeeds() { - return feeds; - } - public static Map<String, Topic> getTopics() { - return topics; - } - public static Map<String, MirrorMaker> getMirrorMakers() { - return mirrors; - } - - static { - try { - appLogger.info( "begin static initialization"); - appLogger.info( "initializing dmaap" ); - DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig(); - if ("true".equalsIgnoreCase(p.getProperty("UsePGSQL", "false"))) { - appLogger.info("Data from database"); - try { - LoadSchema.upgrade(); - } catch (Exception e) { - appLogger.warn("Problem updating DB schema", e); - } - try { - dmaap = new DBSingleton<>(Dmaap.class, "dmaap"); - dcaeLocations = new DBMap<>(DcaeLocation.class, "dcae_location", "dcae_location_name"); - dr_nodes = new DBMap<>(DR_Node.class, "dr_node", "fqdn"); - dr_pubs = new DBMap<>(DR_Pub.class, "dr_pub", "pub_id"); - dr_subs = new DBMap<>(DR_Sub.class, "dr_sub", "sub_id"); - mr_clients = new DBMap<>(MR_Client.class, "mr_client", "mr_client_id"); - mr_clusters = new DBMap<>(MR_Cluster.class, "mr_cluster", "dcae_location_name"); - feeds = new DBMap<>(Feed.class, "feed", "feed_id"); - TableHandler.setSpecialCase("topic", "replication_case", new TopicReplicationTypeHandler()); - topics = new DBMap<>(Topic.class, "topic", "fqtn"); - TableHandler.setSpecialCase("mirror_maker", "topics", new MirrorTopicsHandler()); - mirrors = new DBMap<>(MirrorMaker.class, "mirror_maker", "mm_name"); - } catch (Exception e) { - errorLogger.error("Error initializing database access " + e, e); - System.exit(1); - } - } else { - appLogger.info("Data from memory"); - dmaap = new Singleton<Dmaap>() { - private Dmaap dmaap; - public void remove() { - dmaap = null; - } - public void init(Dmaap val) { - if (dmaap == null) { - dmaap = val; - } - } - public Dmaap get() { - return(dmaap); - } - public void update(Dmaap nd) { - dmaap.setVersion(nd.getVersion()); - dmaap.setTopicNsRoot(nd.getTopicNsRoot()); - dmaap.setDmaapName(nd.getDmaapName()); - dmaap.setDrProvUrl(nd.getDrProvUrl()); - dmaap.setBridgeAdminTopic(nd.getBridgeAdminTopic()); - dmaap.setLoggingUrl(nd.getLoggingUrl()); - dmaap.setNodeKey(nd.getNodeKey()); - dmaap.setAccessKeyOwner(nd.getAccessKeyOwner()); - } - }; - dcaeLocations = new HashMap<>(); - dr_nodes = new HashMap<>(); - dr_pubs = new HashMap<>(); - dr_subs = new HashMap<>(); - mr_clients = new HashMap<>(); - mr_clusters = new HashMap<>(); - feeds = new HashMap<>(); - topics = new HashMap<>(); - mirrors = new HashMap<>(); - } - dmaap.init(new Dmaap("0", "", "", "", "", "", "", "")); - // force initial read from DB, if it exists - @SuppressWarnings("unused") - Dmaap dmx = dmaap.get(); - - // old code in this spot would read from properties file as part of init. - // but all those properties are now set via /dmaap API - - } catch (Exception e) { - errorLogger.error("Error", e); - errorLogger.error(DmaapbcLogMessageEnum.DB_UPDATE_ERROR, e.getMessage()); - } - - } - - public static synchronized String getNextClientId() { - - long id = System.currentTimeMillis(); - if ( id <= lastTime ) { - id = lastTime + 1; - } - lastTime = id; - return Long.toString(id); - } - - + private static long lastTime = 0L; + private static DBType databaseType; + + private enum DBType { + PGSQL, MEMORY + } + + public static Singleton<Dmaap> getDmaap() { + return dmaap; + } + + + public static Map<String, DcaeLocation> getDcaeLocations() { + return dcaeLocations; + } + + public static Map<String, DR_Node> getDr_nodes() { + return dr_nodes; + } + + public static Map<String, DR_Sub> getDr_subs() { + return dr_subs; + } + + public static Map<String, DR_Pub> getDr_pubs() { + return dr_pubs; + } + + public static Map<String, MR_Client> getMr_clients() { + return mr_clients; + } + + + public static Map<String, MR_Cluster> getMr_clusters() { + return mr_clusters; + } + + public static Map<String, Feed> getFeeds() { + return feeds; + } + + public static Map<String, Topic> getTopics() { + return topics; + } + + public static Map<String, MirrorMaker> getMirrorMakers() { + return mirrors; + } + + static { + try { + appLogger.info("begin static initialization"); + appLogger.info("initializing dmaap"); + determineDatabaseType(); + + switch (databaseType) { + case PGSQL: + databaseResourceInit(); + break; + case MEMORY: + inMemoryResourceInit(); + break; + } + + dmaap.init(new Dmaap("0", "", "", "", "", "", "", "")); + // force initial read from DB, if it exists + @SuppressWarnings("unused") + Dmaap dmx = dmaap.get(); + + // old code in this spot would read from properties file as part of init. + // but all those properties are now set via /dmaap API + + } catch (Exception e) { + errorLogger.error("Error", e); + errorLogger.error(DmaapbcLogMessageEnum.DB_UPDATE_ERROR, e.getMessage()); + } + + } + + public static synchronized String getNextClientId() { + + long id = System.currentTimeMillis(); + if (id <= lastTime) { + id = lastTime + 1; + } + lastTime = id; + return Long.toString(id); + } + + public static synchronized void clearDatabase() { + switch (databaseType) { + case PGSQL: + try { + initDatabase(); + } catch (Exception e) { + errorLogger.error("Error initializing database access " + e, e); + } + break; + case MEMORY: + initMemoryDatabase(); + break; + } + } + + private static void inMemoryResourceInit() { + appLogger.info("Data from memory"); + dmaap = new Singleton<Dmaap>() { + private Dmaap dmaap; + + public void remove() { + dmaap = null; + } + + public void init(Dmaap val) { + if (dmaap == null) { + dmaap = val; + } + } + + public Dmaap get() { + return (dmaap); + } + + public void update(Dmaap nd) { + dmaap.setVersion(nd.getVersion()); + dmaap.setTopicNsRoot(nd.getTopicNsRoot()); + dmaap.setDmaapName(nd.getDmaapName()); + dmaap.setDrProvUrl(nd.getDrProvUrl()); + dmaap.setBridgeAdminTopic(nd.getBridgeAdminTopic()); + dmaap.setLoggingUrl(nd.getLoggingUrl()); + dmaap.setNodeKey(nd.getNodeKey()); + dmaap.setAccessKeyOwner(nd.getAccessKeyOwner()); + } + }; + initMemoryDatabase(); + } + + private static void databaseResourceInit() { + appLogger.info("Data from database"); + try { + LoadSchema.upgrade(); + } catch (Exception e) { + appLogger.warn("Problem updating DB schema", e); + } + try { + dmaap = new DBSingleton<>(Dmaap.class, "dmaap"); + TableHandler.setSpecialCase("topic", "replication_case", new TopicReplicationTypeHandler()); + TableHandler.setSpecialCase("mirror_maker", "topics", new MirrorTopicsHandler()); + initDatabase(); + } catch (Exception e) { + errorLogger.error("Error initializing database access " + e, e); + System.exit(1); + } + } + + private static class MirrorTopicsHandler implements DBFieldHandler.SqlOp { + + public Object get(ResultSet rs, int index) throws Exception { + String val = rs.getString(index); + if (val == null) { + return (null); + } + List<String> rv = new ArrayList<>(); + for (String s : val.split(",")) { + rv.add(new String(s)); + } + return (rv); + } + + public void set(PreparedStatement ps, int index, Object val) throws Exception { + if (val == null) { + ps.setString(index, null); + return; + } + @SuppressWarnings("unchecked") + List<String> xv = (List<String>) val; + StringBuilder sb = new StringBuilder(); + String sep = ""; + for (Object o : xv) { + String rv = (String) o; + sb.append(sep).append(DBFieldHandler.fesc(rv)); + sep = ","; + } + ps.setString(index, sb.toString()); + } + } + + private static class TopicReplicationTypeHandler implements DBFieldHandler.SqlOp { + + public Object get(ResultSet rs, int index) throws Exception { + int val = rs.getInt(index); + + return (ReplicationType.valueOf(val)); + } + + public void set(PreparedStatement ps, int index, Object val) throws Exception { + if (val == null) { + ps.setInt(index, 0); + return; + } + @SuppressWarnings("unchecked") + ReplicationType rep = (ReplicationType) val; + ps.setInt(index, rep.getValue()); + } + } + + private static void initMemoryDatabase() { + dcaeLocations = new HashMap<>(); + dr_nodes = new HashMap<>(); + dr_pubs = new HashMap<>(); + dr_subs = new HashMap<>(); + mr_clients = new HashMap<>(); + mr_clusters = new HashMap<>(); + feeds = new HashMap<>(); + topics = new HashMap<>(); + mirrors = new HashMap<>(); + } + private static void initDatabase() throws Exception { + dcaeLocations = new DBMap<>(DcaeLocation.class, "dcae_location", "dcae_location_name"); + dr_nodes = new DBMap<>(DR_Node.class, "dr_node", "fqdn"); + dr_pubs = new DBMap<>(DR_Pub.class, "dr_pub", "pub_id"); + dr_subs = new DBMap<>(DR_Sub.class, "dr_sub", "sub_id"); + mr_clients = new DBMap<>(MR_Client.class, "mr_client", "mr_client_id"); + mr_clusters = new DBMap<>(MR_Cluster.class, "mr_cluster", "dcae_location_name"); + feeds = new DBMap<>(Feed.class, "feed", "feed_id"); + topics = new DBMap<>(Topic.class, "topic", "fqtn"); + mirrors = new DBMap<>(MirrorMaker.class, "mirror_maker", "mm_name"); + } + private static void determineDatabaseType() { + DmaapConfig dmaapConfig = (DmaapConfig) DmaapConfig.getConfig(); + String isPgSQLset = dmaapConfig.getProperty("UsePGSQL", "false"); + databaseType = isPgSQLset.equalsIgnoreCase("true") ? DBType.PGSQL : DBType.MEMORY; + } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/ApiError.java b/src/main/java/org/onap/dmaap/dbcapi/model/ApiError.java index 2e05740..c67e55b 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/model/ApiError.java +++ b/src/main/java/org/onap/dmaap/dbcapi/model/ApiError.java @@ -21,10 +21,11 @@ package org.onap.dmaap.dbcapi.model; import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; import java.util.Objects; @XmlRootElement -public class ApiError { +public class ApiError implements Serializable { private int code; private String message; private String fields; diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/DR_Node.java b/src/main/java/org/onap/dmaap/dbcapi/model/DR_Node.java index a85f040..4b2ef90 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/model/DR_Node.java +++ b/src/main/java/org/onap/dmaap/dbcapi/model/DR_Node.java @@ -21,6 +21,7 @@ package org.onap.dmaap.dbcapi.model; import javax.xml.bind.annotation.XmlRootElement; +import java.util.Objects; @XmlRootElement public class DR_Node extends DmaapObject { @@ -75,4 +76,19 @@ public class DR_Node extends DmaapObject { this.version = version; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DR_Node dr_node = (DR_Node) o; + return Objects.equals(fqdn, dr_node.fqdn) && + Objects.equals(dcaeLocationName, dr_node.dcaeLocationName) && + Objects.equals(hostName, dr_node.hostName) && + Objects.equals(version, dr_node.version); + } + + @Override + public int hashCode() { + return Objects.hash(fqdn, dcaeLocationName, hostName, version); + } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/DR_Sub.java b/src/main/java/org/onap/dmaap/dbcapi/model/DR_Sub.java index 9d30021..8ac0880 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/model/DR_Sub.java +++ b/src/main/java/org/onap/dmaap/dbcapi/model/DR_Sub.java @@ -331,7 +331,7 @@ public class DR_Sub extends DmaapObject { @Override public String toString() { - String rc = String.format ( "DR_Sub: {dcaeLocationName=%s username=%s userpwd=%s feedId=%s deliveryURL=%s logURL=%s subid=%s use100=%s suspended=%s owner=%s}", + return String.format ( "DR_Sub: {dcaeLocationName=%s username=%s userpwd=%s feedId=%s deliveryURL=%s logURL=%s subid=%s use100=%s suspended=%s owner=%s}", dcaeLocationName, username, userpwd, @@ -343,6 +343,49 @@ public class DR_Sub extends DmaapObject { suspended, owner ); - return rc; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DR_Sub drSub = (DR_Sub) o; + + if (use100 != drSub.use100) { + return false; + } + if (suspended != drSub.suspended) { + return false; + } + if (!dcaeLocationName.equals(drSub.dcaeLocationName)) { + return false; + } + if (!username.equals(drSub.username)) { + return false; + } + if (!userpwd.equals(drSub.userpwd)) { + return false; + } + if (!feedId.equals(drSub.feedId)) { + return false; + } + return subId.equals(drSub.subId); + } + + @Override + public int hashCode() { + int result = dcaeLocationName.hashCode(); + result = 31 * result + username.hashCode(); + result = 31 * result + userpwd.hashCode(); + result = 31 * result + feedId.hashCode(); + result = 31 * result + subId.hashCode(); + result = 31 * result + (use100 ? 1 : 0); + result = 31 * result + (suspended ? 1 : 0); + return result; } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/AAFAuthenticationFilter.java b/src/main/java/org/onap/dmaap/dbcapi/resources/AAFAuthenticationFilter.java new file mode 100644 index 0000000..8739511 --- /dev/null +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/AAFAuthenticationFilter.java @@ -0,0 +1,128 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dmaap + * ================================================================================ + * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dmaap.dbcapi.resources; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import org.apache.log4j.Logger; +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.dmaap.dbcapi.model.ApiError; +import org.onap.dmaap.dbcapi.util.DmaapConfig; + +public class AAFAuthenticationFilter implements Filter { + + private static final Logger LOGGER = Logger.getLogger(AAFAuthenticationFilter.class.getName()); + static final String CADI_PROPERTIES = "cadi.properties"; + static final String AAF_AUTHN_FLAG = "UseAAF"; + + private boolean isAafEnabled; + private CadiFilter cadiFilter; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + DmaapConfig dmaapConfig = getConfig(); + String flag = dmaapConfig.getProperty(AAF_AUTHN_FLAG, "false"); + isAafEnabled = "true".equalsIgnoreCase(flag); + initCadi(dmaapConfig); + } + + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + + if(isAafEnabled) { + cadiFilter.doFilter(servletRequest, servletResponse, filterChain); + updateResponseBody((HttpServletResponse)servletResponse); + } else { + filterChain.doFilter(servletRequest, servletResponse); + } + } + + private void updateResponseBody(HttpServletResponse httpResponse) + throws IOException { + if(httpResponse.getStatus() == 401) { + String errorMsg = "invalid or no credentials provided"; + LOGGER.error(errorMsg); + httpResponse.setContentType("application/json"); + httpResponse.setCharacterEncoding("UTF-8"); + httpResponse.getWriter().print(buildErrorResponse(errorMsg)); + httpResponse.getWriter().flush(); + } + } + + private String buildErrorResponse(String msg) { + try { + return new ObjectMapper().writeValueAsString(new ApiError(HttpStatus.UNAUTHORIZED_401, msg, "Authentication")); + } catch (JsonProcessingException e) { + LOGGER.warn("Could not serialize response entity: " + e.getMessage()); + return ""; + } + } + + + @Override + public void destroy() { + //nothing to cleanup + } + + private void initCadi(DmaapConfig dmaapConfig) throws ServletException { + if(isAafEnabled) { + try { + String cadiPropertiesFile = dmaapConfig.getProperty(CADI_PROPERTIES); + if(cadiPropertiesFile != null && !cadiPropertiesFile.isEmpty()) { + cadiFilter = new CadiFilter(new PropAccess(cadiPropertiesFile)); + } else { + throw new ServletException("Cannot initialize CADI filter.CADI properties not available."); + } + } catch (ServletException e) { + LOGGER.error("CADI init error :" + e.getMessage()); + throw e; + } + } + } + + DmaapConfig getConfig() { + return (DmaapConfig) DmaapConfig.getConfig(); + } + + //tests only + CadiFilter getCadiFilter() { + return cadiFilter; + } + + void setCadiFilter(CadiFilter cadiFilter) { + this.cadiFilter = cadiFilter; + } + + boolean isAafEnabled() { + return isAafEnabled; + } +} diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/AAFAuthorizationFilter.java b/src/main/java/org/onap/dmaap/dbcapi/resources/AAFAuthorizationFilter.java new file mode 100644 index 0000000..5bc3dec --- /dev/null +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/AAFAuthorizationFilter.java @@ -0,0 +1,116 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dmaap + * ================================================================================ + * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dmaap.dbcapi.resources; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.log4j.Logger; +import org.eclipse.jetty.http.HttpStatus; +import org.onap.dmaap.dbcapi.model.ApiError; +import org.onap.dmaap.dbcapi.service.DmaapService; +import org.onap.dmaap.dbcapi.util.DmaapConfig; +import org.onap.dmaap.dbcapi.util.PermissionBuilder; + +public class AAFAuthorizationFilter implements Filter{ + + private static final Logger LOGGER = Logger.getLogger(AAFAuthenticationFilter.class.getName()); + static final String AAF_AUTHZ_FLAG = "UseAAF"; + private boolean isAafEnabled = false; + + private PermissionBuilder permissionBuilder; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + DmaapConfig dmaapConfig = getConfig(); + isAafEnabled = "true".equalsIgnoreCase(dmaapConfig.getProperty(AAF_AUTHZ_FLAG, "false")); + if(isAafEnabled) { + permissionBuilder = new PermissionBuilder(dmaapConfig, getDmaapService()); + } + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + + if(isAafEnabled) { + HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; + permissionBuilder.updateDmaapInstance(); + String permission = permissionBuilder.buildPermission(httpRequest); + + if (httpRequest.isUserInRole(permission)) { + LOGGER.info("User " + httpRequest.getUserPrincipal().getName() + " has permission " + permission); + filterChain.doFilter(servletRequest, servletResponse); + } else { + String msg = "User " + httpRequest.getUserPrincipal().getName() + " does not have permission " + permission; + LOGGER.error(msg); + ((HttpServletResponse) servletResponse).setStatus(HttpStatus.FORBIDDEN_403); + servletResponse.setContentType("application/json"); + servletResponse.setCharacterEncoding("UTF-8"); + servletResponse.getWriter().print(buildErrorResponse(msg)); + servletResponse.getWriter().flush(); + } + } else { + filterChain.doFilter(servletRequest, servletResponse); + } + } + + @Override + public void destroy() { + //nothing to cleanup + } + + DmaapConfig getConfig() { + return (DmaapConfig) DmaapConfig.getConfig(); + } + + DmaapService getDmaapService() { + return new DmaapService(); + } + + private String buildErrorResponse(String msg) { + try { + return new ObjectMapper().writeValueAsString(new ApiError(HttpStatus.FORBIDDEN_403, msg, "Authorization")); + } catch (JsonProcessingException e) { + LOGGER.warn("Could not serialize response entity: " + e.getMessage()); + return ""; + } + } + + PermissionBuilder getPermissionBuilder() { + return permissionBuilder; + } + + void setPermissionBuilder(PermissionBuilder permissionBuilder) { + this.permissionBuilder = permissionBuilder; + } + + void setAafEnabled(boolean aafEnabled) { + isAafEnabled = aafEnabled; + } +} diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/AuthorizationFilter.java b/src/main/java/org/onap/dmaap/dbcapi/resources/AuthorizationFilter.java index fd5b4aa..3ed5717 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/AuthorizationFilter.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/AuthorizationFilter.java @@ -26,33 +26,44 @@ import javax.ws.rs.container.ContainerRequestFilter; import org.apache.log4j.Logger; import org.onap.dmaap.dbcapi.authentication.AuthenticationErrorException; import org.onap.dmaap.dbcapi.service.ApiService; +import org.onap.dmaap.dbcapi.util.DmaapConfig; @Authorization public class AuthorizationFilter implements ContainerRequestFilter { - - private Logger logger = Logger.getLogger(AuthorizationFilter.class.getName()); - private ResponseBuilder responseBuilder = new ResponseBuilder(); - + + private static final String AAF_FLAG = "UseAAF"; + private final Logger logger = Logger.getLogger(AuthorizationFilter.class.getName()); + private final ResponseBuilder responseBuilder = new ResponseBuilder(); + private final boolean isAafEnabled; + + + public AuthorizationFilter() { + DmaapConfig dmaapConfig = (DmaapConfig) DmaapConfig.getConfig(); + String flag = dmaapConfig.getProperty(AAF_FLAG, "false"); + isAafEnabled = "true".equalsIgnoreCase(flag); + } + @Override public void filter(ContainerRequestContext requestContext) { - ApiService apiResp = new ApiService() - .setAuth( requestContext.getHeaderString("Authorization") ) - .setUriPath(requestContext.getUriInfo().getPath()) - .setHttpMethod( requestContext.getMethod() ) - .setRequestId( requestContext.getHeaderString("X-ECOMP-RequestID") ); - - try { - apiResp.checkAuthorization(); - } catch ( AuthenticationErrorException ae ) { - logger.error("Error", ae); - requestContext.abortWith( responseBuilder.unauthorized( apiResp.getErr().getMessage() ) ); - } catch ( Exception e ) { - logger.error("Error", e); - requestContext.abortWith( responseBuilder.unavailable() ); - } + if(!isAafEnabled) { + ApiService apiResp = new ApiService() + .setAuth(requestContext.getHeaderString("Authorization")) + .setUriPath(requestContext.getUriInfo().getPath()) + .setHttpMethod(requestContext.getMethod()) + .setRequestId(requestContext.getHeaderString("X-ECOMP-RequestID")); + try { + apiResp.checkAuthorization(); + } catch (AuthenticationErrorException ae) { + logger.error("Error", ae); + requestContext.abortWith(responseBuilder.unauthorized(apiResp.getErr().getMessage())); + } catch (Exception e) { + logger.error("Error", e); + requestContext.abortWith(responseBuilder.unavailable()); + } + } } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/DR_NodeResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/DR_NodeResource.java index 029222e..f001136 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/DR_NodeResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/DR_NodeResource.java @@ -42,7 +42,6 @@ import javax.ws.rs.core.Response; import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; import org.onap.dmaap.dbcapi.model.ApiError; import org.onap.dmaap.dbcapi.model.DR_Node; -import org.onap.dmaap.dbcapi.service.ApiService; import org.onap.dmaap.dbcapi.service.DR_NodeService; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; @@ -57,6 +56,7 @@ public class DR_NodeResource extends BaseLoggingClass { private DR_NodeService dr_nodeService = new DR_NodeService(); private ResponseBuilder responseBuilder = new ResponseBuilder(); + private RequiredChecker checker = new RequiredChecker(); @GET @ApiOperation( value = "return DR_Node details", @@ -82,23 +82,22 @@ public class DR_NodeResource extends BaseLoggingClass { @ApiResponse( code = 200, message = "Success", response = DR_Node.class), @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) - public Response addDr_Node( - DR_Node node - ) { - ApiService resp = new ApiService(); + public Response addDr_Node(DR_Node node) { + + ApiError apiError = new ApiError(); try { - resp.required( "dcaeLocation", node.getDcaeLocationName(), ""); - resp.required( "fqdn", node.getFqdn(), ""); + checker.required( "dcaeLocation", node.getDcaeLocationName()); + checker.required( "fqdn", node.getFqdn()); } catch ( RequiredFieldException rfe ) { return responseBuilder.error(new ApiError(BAD_REQUEST.getStatusCode(), "missing required field", "dcaeLocation, fqdn")); } - DR_Node nNode = dr_nodeService.addDr_Node(node, resp.getErr()); - if ( resp.getErr().is2xx()) { + DR_Node nNode = dr_nodeService.addDr_Node(node, apiError); + if (apiError.is2xx()) { return responseBuilder.success(nNode); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } @PUT @@ -110,24 +109,23 @@ public class DR_NodeResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{fqdn}") - public Response updateDr_Node( - @PathParam("fqdn") String name, - DR_Node node - ) { - ApiService resp = new ApiService(); + public Response updateDr_Node(@PathParam("fqdn") String name, DR_Node node) { + + ApiError apiError = new ApiError(); try { - resp.required( "dcaeLocation", name, ""); - resp.required( "fqdn", node.getFqdn(), ""); + checker.required( "dcaeLocation", node.getDcaeLocationName()); + checker.required( "fqdn", node.getFqdn()); } catch ( RequiredFieldException rfe ) { - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(new ApiError(BAD_REQUEST.getStatusCode(), + "missing required field", "dcaeLocation, fqdn")); } node.setFqdn(name); - DR_Node nNode = dr_nodeService.updateDr_Node(node, resp.getErr()); - if ( resp.getErr().is2xx()) { + DR_Node nNode = dr_nodeService.updateDr_Node(node, apiError); + if (apiError.is2xx()) { return responseBuilder.success(nNode); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } @DELETE @@ -140,22 +138,16 @@ public class DR_NodeResource extends BaseLoggingClass { }) @Path("/{fqdn}") public Response deleteDr_Node( - @PathParam("fqdn") String name - ){ + @PathParam("fqdn") String name){ - ApiService resp = new ApiService(); - try { - resp.required( "fqdn", name, ""); - } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); - } - dr_nodeService.removeDr_Node(name, resp.getErr()); - if ( resp.getErr().is2xx() ) { + ApiError apiError = new ApiError(); + + dr_nodeService.removeDr_Node(name, apiError); + if (apiError.is2xx()) { return responseBuilder.success(NO_CONTENT.getStatusCode(), null); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } @GET @@ -167,15 +159,14 @@ public class DR_NodeResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{fqdn}") - public Response get( - @PathParam("fqdn") String name - ) { - ApiService resp = new ApiService(); + public Response get(@PathParam("fqdn") String name) { + + ApiError apiError = new ApiError(); - DR_Node nNode = dr_nodeService.getDr_Node( name, resp.getErr() ); - if ( resp.getErr().is2xx() ) { + DR_Node nNode = dr_nodeService.getDr_Node( name, apiError ); + if (apiError.is2xx()) { return responseBuilder.success(nNode); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/DR_PubResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/DR_PubResource.java index 9c2ae21..928a7e2 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/DR_PubResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/DR_PubResource.java @@ -46,7 +46,6 @@ import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; import org.onap.dmaap.dbcapi.model.ApiError; import org.onap.dmaap.dbcapi.model.DR_Pub; import org.onap.dmaap.dbcapi.model.Feed; -import org.onap.dmaap.dbcapi.service.ApiService; import org.onap.dmaap.dbcapi.service.DR_PubService; import org.onap.dmaap.dbcapi.service.FeedService; @@ -60,6 +59,7 @@ public class DR_PubResource extends BaseLoggingClass { private DR_PubService dr_pubService = new DR_PubService(); private ResponseBuilder responseBuilder = new ResponseBuilder(); + private RequiredChecker checker = new RequiredChecker(); @GET @ApiOperation( value = "return DR_Pub details", @@ -86,47 +86,45 @@ public class DR_PubResource extends BaseLoggingClass { @ApiResponse( code = 200, message = "Success", response = DR_Pub.class), @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) - public Response addDr_Pub( - DR_Pub pub - ) { - ApiService resp = new ApiService(); + public Response addDr_Pub(DR_Pub pub) { + ApiError apiError = new ApiError(); FeedService feeds = new FeedService(); Feed fnew = null; logger.info( "Entry: POST /dr_pubs"); try { - resp.required( "feedId", pub.getFeedId(), ""); + checker.required( "feedId", pub.getFeedId()); } catch ( RequiredFieldException rfe ) { try { - resp.required( "feedName", pub.getFeedName(), ""); + checker.required( "feedName", pub.getFeedName()); }catch ( RequiredFieldException rfe2 ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe2.getApiError().toString() ); + return responseBuilder.error(rfe2.getApiError()); } // if we found a FeedName instead of a FeedId then try to look it up. List<Feed> nfeeds = feeds.getAllFeeds( pub.getFeedName(), pub.getFeedVersion(), "equals"); if ( nfeeds.size() != 1 ) { logger.debug( "Attempt to match "+ pub.getFeedName() + " ver="+pub.getFeedVersion() + " matched " + nfeeds.size() ); - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } fnew = nfeeds.get(0); } try { - resp.required( "dcaeLocationName", pub.getDcaeLocationName(), ""); + checker.required( "dcaeLocationName", pub.getDcaeLocationName()); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.getErr().toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } // we may have fnew already if located by FeedName if ( fnew == null ) { - fnew = feeds.getFeed( pub.getFeedId(), resp.getErr() ); + fnew = feeds.getFeed(pub.getFeedId(), apiError); } if ( fnew == null ) { logger.info( "Specified feed " + pub.getFeedId() + " or " + pub.getFeedName() + " not known to Bus Controller"); - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } ArrayList<DR_Pub> pubs = fnew.getPubs(); @@ -142,15 +140,15 @@ public class DR_PubResource extends BaseLoggingClass { } pubs.add( pub ); fnew.setPubs(pubs); - fnew = feeds.updateFeed( fnew, resp.getErr() ); + fnew = feeds.updateFeed(fnew, apiError); - if ( ! resp.getErr().is2xx()) { - return responseBuilder.error(resp.getErr()); + if (!apiError.is2xx()) { + return responseBuilder.error(apiError); } pubs = fnew.getPubs(); logger.info( "num existing pubs after = " + pubs.size() ); - DR_Pub pnew = dr_pubService.getDr_Pub(pub.getPubId(), resp.getErr()); + DR_Pub pnew = dr_pubService.getDr_Pub(pub.getPubId(), apiError); return responseBuilder.success(Status.CREATED.getStatusCode(), pnew); } @@ -163,10 +161,7 @@ public class DR_PubResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{pubId}") - public Response updateDr_Pub( - @PathParam("pubId") String name, - DR_Pub pub - ) { + public Response updateDr_Pub(@PathParam("pubId") String name, DR_Pub pub) { logger.info( "Entry: PUT /dr_pubs"); pub.setPubId(name); DR_Pub res = dr_pubService.updateDr_Pub(pub); @@ -182,33 +177,31 @@ public class DR_PubResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{pubId}") - public Response deleteDr_Pub( - @PathParam("pubId") String id - ){ + public Response deleteDr_Pub(@PathParam("pubId") String id){ - ApiService resp = new ApiService(); + ApiError apiError = new ApiError(); try { - resp.required( "pubId", id, ""); + checker.required( "pubId", id); } catch ( RequiredFieldException rfe ) { - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(rfe.getApiError()); } - DR_Pub pub = dr_pubService.getDr_Pub( id, resp.getErr() ); - if ( ! resp.getErr().is2xx()) { - return responseBuilder.error(resp.getErr()); + DR_Pub pub = dr_pubService.getDr_Pub(id, apiError); + if ( !apiError.is2xx()) { + return responseBuilder.error(apiError); } FeedService feeds = new FeedService(); - Feed fnew = feeds.getFeed( pub.getFeedId(), resp.getErr() ); + Feed fnew = feeds.getFeed(pub.getFeedId(), apiError); if ( fnew == null ) { logger.info( "Specified feed " + pub.getFeedId() + " not known to Bus Controller"); - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } ArrayList<DR_Pub> pubs = fnew.getPubs(); if ( pubs.size() == 1 ) { - resp.setCode(Status.BAD_REQUEST.getStatusCode()); - resp.setMessage( "Can't delete the last publisher of a feed"); - return responseBuilder.error(resp.getErr()); + apiError.setCode(Status.BAD_REQUEST.getStatusCode()); + apiError.setMessage( "Can't delete the last publisher of a feed"); + return responseBuilder.error(apiError); } for( Iterator<DR_Pub> i = pubs.iterator(); i.hasNext(); ) { @@ -218,14 +211,14 @@ public class DR_PubResource extends BaseLoggingClass { } } fnew.setPubs(pubs); - fnew = feeds.updateFeed( fnew, resp.getErr() ); - if ( ! resp.getErr().is2xx()) { - return responseBuilder.error(resp.getErr()); + fnew = feeds.updateFeed(fnew,apiError); + if (!apiError.is2xx()) { + return responseBuilder.error(apiError); } - dr_pubService.removeDr_Pub(id, resp.getErr() ); - if ( ! resp.getErr().is2xx()) { - return responseBuilder.error(resp.getErr()); + dr_pubService.removeDr_Pub(id, apiError); + if (!apiError.is2xx()) { + return responseBuilder.error(apiError); } return responseBuilder.success(Status.NO_CONTENT.getStatusCode(), null); } @@ -239,20 +232,18 @@ public class DR_PubResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{pubId}") - public Response get( - @PathParam("pubId") String id - ) { - ApiService resp = new ApiService(); + public Response get(@PathParam("pubId") String id) { + ApiError apiError = new ApiError(); try { - resp.required( "feedId", id, ""); + checker.required( "feedId", id); } catch ( RequiredFieldException rfe ) { - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(rfe.getApiError()); } - DR_Pub pub = dr_pubService.getDr_Pub( id, resp.getErr() ); - if ( ! resp.getErr().is2xx()) { - resp.getErr(); + DR_Pub pub = dr_pubService.getDr_Pub(id, apiError); + if (!apiError.is2xx()) { + return responseBuilder.error(apiError); } return responseBuilder.success(Status.OK.getStatusCode(), pub); } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/DR_SubResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/DR_SubResource.java index 01ac059..2fa6ccd 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/DR_SubResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/DR_SubResource.java @@ -22,6 +22,7 @@ package org.onap.dmaap.dbcapi.resources; +import com.google.common.collect.Iterables; import java.util.ArrayList; import java.util.List; @@ -42,7 +43,6 @@ import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; import org.onap.dmaap.dbcapi.model.ApiError; import org.onap.dmaap.dbcapi.model.DR_Sub; import org.onap.dmaap.dbcapi.model.Feed; -import org.onap.dmaap.dbcapi.service.ApiService; import org.onap.dmaap.dbcapi.service.DR_SubService; import org.onap.dmaap.dbcapi.service.FeedService; @@ -62,6 +62,7 @@ import static javax.ws.rs.core.Response.Status.CREATED; public class DR_SubResource extends BaseLoggingClass { private ResponseBuilder responseBuilder = new ResponseBuilder(); + private RequiredChecker checker = new RequiredChecker(); @GET @ApiOperation( value = "return DR_Sub details", @@ -88,52 +89,56 @@ public class DR_SubResource extends BaseLoggingClass { @ApiResponse( code = 200, message = "Success", response = DR_Sub.class), @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) - public Response addDr_Sub( - DR_Sub sub - ) { - - ApiService resp = new ApiService(); + public Response addDr_Sub(DR_Sub sub) { + + ApiError apiError = new ApiError(); FeedService feeds = new FeedService(); Feed fnew = null; try { - resp.required( "feedId", sub.getFeedId(), ""); + checker.required( "feedId", sub.getFeedId()); } catch ( RequiredFieldException rfe ) { try { - resp.required( "feedName", sub.getFeedName(), ""); + checker.required( "feedName", sub.getFeedName()); }catch ( RequiredFieldException rfe2 ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe2.getApiError().toString() ); + return responseBuilder.error(rfe2.getApiError()); } // if we found a FeedName instead of a FeedId then try to look it up. List<Feed> nfeeds = feeds.getAllFeeds( sub.getFeedName(), sub.getFeedVersion(), "equals"); - if ( nfeeds.size() != 1 ) { + if ( nfeeds.isEmpty() ) { + apiError.setCode(Status.NOT_FOUND.getStatusCode()); + apiError.setFields("feedName"); + return responseBuilder.error(apiError); + } else if (nfeeds.size() > 1) { logger.debug( "Attempt to match "+ sub.getFeedName() + " ver="+sub.getFeedVersion() + " matched " + nfeeds.size() ); - return responseBuilder.error(resp.getErr()); + apiError.setCode(Status.CONFLICT.getStatusCode()); + apiError.setFields("feedName"); + return responseBuilder.error(apiError); } - fnew = nfeeds.get(0); + fnew = Iterables.getOnlyElement(nfeeds); } try { - resp.required( "dcaeLocationName", sub.getDcaeLocationName(), ""); + checker.required( "dcaeLocationName", sub.getDcaeLocationName()); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } // we may have fnew already if located by FeedName if ( fnew == null ) { - fnew = feeds.getFeed( sub.getFeedId(), resp.getErr() ); + fnew = feeds.getFeed( sub.getFeedId(), apiError); } if ( fnew == null ) { logger.warn( "Specified feed " + sub.getFeedId() + " or " + sub.getFeedName() + " not known to Bus Controller"); - resp.setCode(Status.NOT_FOUND.getStatusCode()); - return responseBuilder.error(resp.getErr()); + apiError.setCode(Status.NOT_FOUND.getStatusCode()); + return responseBuilder.error(apiError); } DR_SubService dr_subService = new DR_SubService( fnew.getSubscribeURL()); ArrayList<DR_Sub> subs = fnew.getSubs(); logger.info( "num existing subs before = " + subs.size() ); - DR_Sub snew = dr_subService.addDr_Sub(sub, resp.getErr() ); - if ( ! resp.getErr().is2xx() ) { - return responseBuilder.error(resp.getErr()); + DR_Sub snew = dr_subService.addDr_Sub(sub, apiError); + if (!apiError.is2xx()) { + return responseBuilder.error(apiError); } subs.add( snew ); logger.info( "num existing subs after = " + subs.size() ); @@ -153,36 +158,33 @@ public class DR_SubResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{subId}") - public Response updateDr_Sub( - @PathParam("subId") String name, - DR_Sub sub - ) { + public Response updateDr_Sub(@PathParam("subId") String name, DR_Sub sub) { - ApiService resp = new ApiService(); + ApiError apiError = new ApiError(); try { - resp.required( "subId", name, ""); - resp.required( "feedId", sub.getFeedId(), ""); - resp.required( "dcaeLocationName", sub.getDcaeLocationName(), ""); + checker.required( "subId", name); + checker.required( "feedId", sub.getFeedId()); + checker.required( "dcaeLocationName", sub.getDcaeLocationName()); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } FeedService feeds = new FeedService(); - Feed fnew = feeds.getFeed( sub.getFeedId(), resp.getErr() ); + Feed fnew = feeds.getFeed(sub.getFeedId(), apiError); if ( fnew == null ) { logger.warn( "Specified feed " + sub.getFeedId() + " not known to Bus Controller"); - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } DR_SubService dr_subService = new DR_SubService(); sub.setSubId(name); - DR_Sub nsub = dr_subService.updateDr_Sub(sub, resp.getErr() ); + DR_Sub nsub = dr_subService.updateDr_Sub(sub, apiError); if ( nsub != null && nsub.isStatusValid() ) { return responseBuilder.success(nsub); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } @DELETE @@ -194,22 +196,20 @@ public class DR_SubResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{subId}") - public Response deleteDr_Sub( - @PathParam("subId") String id - ){ + public Response deleteDr_Sub(@PathParam("subId") String id){ - ApiService resp = new ApiService(); + ApiError apiError = new ApiError(); try { - resp.required( "subId", id, ""); + checker.required( "subId", id); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } DR_SubService dr_subService = new DR_SubService(); - dr_subService.removeDr_Sub(id, resp.getErr() ); - if ( ! resp.getErr().is2xx() ) { - return responseBuilder.error(resp.getErr()); + dr_subService.removeDr_Sub(id, apiError); + if (!apiError.is2xx() ) { + return responseBuilder.error(apiError); } return responseBuilder.success(Status.NO_CONTENT.getStatusCode(), null ); } @@ -223,22 +223,21 @@ public class DR_SubResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{subId}") - public Response get( - @PathParam("subId") String id - ) { - ApiService resp = new ApiService(); + public Response get(@PathParam("subId") String id) { + + ApiError apiError = new ApiError(); try { - resp.required( "subId", id, ""); + checker.required( "subId", id); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } DR_SubService dr_subService = new DR_SubService(); - DR_Sub sub = dr_subService.getDr_Sub( id, resp.getErr() ); + DR_Sub sub = dr_subService.getDr_Sub(id, apiError); if ( sub != null && sub.isStatusValid() ) { return responseBuilder.success(sub); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/DmaapResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/DmaapResource.java index d7fb507..955cab7 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/DmaapResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/DmaapResource.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,11 +24,14 @@ package org.onap.dmaap.dbcapi.resources; - import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; +import org.onap.dmaap.dbcapi.model.ApiError; +import org.onap.dmaap.dbcapi.model.Dmaap; +import org.onap.dmaap.dbcapi.service.DmaapService; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -41,13 +44,6 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; -import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; -import org.onap.dmaap.dbcapi.model.ApiError; -import org.onap.dmaap.dbcapi.model.Dmaap; -import org.onap.dmaap.dbcapi.service.ApiService; -import org.onap.dmaap.dbcapi.service.DmaapService; - - @Path("/dmaap") @Api( value= "dmaap", description = "Endpoint for this instance of DMaaP object containing values for this OpenDCAE deployment" ) @@ -59,7 +55,8 @@ public class DmaapResource extends BaseLoggingClass { private DmaapService dmaapService = new DmaapService(); private ResponseBuilder responseBuilder = new ResponseBuilder(); - + private RequiredChecker checker = new RequiredChecker(); + @GET @ApiOperation( value = "return dmaap details", notes = "returns the `dmaap` object, which contains system wide configuration settings", response = Dmaap.class) @ApiResponses( value = { @@ -71,7 +68,7 @@ public class DmaapResource extends BaseLoggingClass { Dmaap d = dmaapService.getDmaap(); return responseBuilder.success(d); } - + @POST @ApiOperation( value = "return dmaap details", notes = "Create a new DMaaP set system wide configuration settings for the *dcaeEnvironment*. Deprecated with introduction of persistence in 1610.", response = Dmaap.class) @ApiResponses( value = { @@ -79,26 +76,22 @@ public class DmaapResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) public Response addDmaap( Dmaap obj ) { - ApiService check = new ApiService(); - try { //check for required fields - check.required( "dmaapName", obj.getDmaapName(), "^\\S+$" ); //no white space allowed in dmaapName - check.required( "dmaapProvUrl", obj.getDrProvUrl(), "" ); - check.required( "topicNsRoot", obj.getTopicNsRoot(), "" ); - check.required( "bridgeAdminTopic", obj.getBridgeAdminTopic(), "" ); + try { + validateRequiredFields(obj); } catch( RequiredFieldException rfe ) { - return responseBuilder.error(check.getErr()); + return responseBuilder.error(rfe.getApiError()); } - + Dmaap d = dmaapService.addDmaap(obj); if ( d == null ) { return responseBuilder.notFound(); - } + } return responseBuilder.success(d); } - + @PUT @ApiOperation( value = "return dmaap details", notes = "Update system settings for *dcaeEnvironment*.", response = Dmaap.class) @ApiResponses( value = { @@ -106,23 +99,25 @@ public class DmaapResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) public Response updateDmaap( Dmaap obj ) { - ApiService check = new ApiService(); - try { //check for required fields - check.required( "dmaapName", obj.getDmaapName(), "^\\S+$" ); //no white space allowed in dmaapName - check.required( "dmaapProvUrl", obj.getDrProvUrl(), "" ); - check.required( "topicNsRoot", obj.getTopicNsRoot(), "" ); - check.required( "bridgeAdminTopic", obj.getBridgeAdminTopic(), "" ); + try { + validateRequiredFields(obj); } catch( RequiredFieldException rfe ) { - return responseBuilder.error(check.getErr()); + return responseBuilder.error(rfe.getApiError()); } + Dmaap d = dmaapService.updateDmaap(obj); if ( d != null ) { return responseBuilder.success(d); } else { return responseBuilder.notFound(); - } + } + } + + private void validateRequiredFields(Dmaap obj) throws RequiredFieldException { + checker.required( "dmaapName", obj.getDmaapName(), "^\\S+$" ); //no white space allowed in dmaapName + checker.required( "dmaapProvUrl", obj.getDrProvUrl()); + checker.required( "topicNsRoot", obj.getTopicNsRoot()); + checker.required( "bridgeAdminTopic", obj.getBridgeAdminTopic()); } - - } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/FeedResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/FeedResource.java index 382d88c..6589c0d 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/FeedResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/FeedResource.java @@ -46,7 +46,6 @@ import org.onap.dmaap.dbcapi.model.ApiError; import org.onap.dmaap.dbcapi.model.DR_Pub; import org.onap.dmaap.dbcapi.model.Feed; import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status; -import org.onap.dmaap.dbcapi.service.ApiService; import org.onap.dmaap.dbcapi.service.FeedService; @@ -58,6 +57,7 @@ import org.onap.dmaap.dbcapi.service.FeedService; public class FeedResource extends BaseLoggingClass { private ResponseBuilder responseBuilder = new ResponseBuilder(); + private RequiredChecker checker = new RequiredChecker(); @GET @ApiOperation( value = "return Feed details", @@ -93,46 +93,46 @@ public class FeedResource extends BaseLoggingClass { @WebParam(name = "feed") Feed feed, @QueryParam("useExisting") String useExisting) { - ApiService resp = new ApiService(); + ApiError apiError = new ApiError(); try { - resp.required( "feedName", feed.getFeedName(), ""); - resp.required( "feedVersion", feed.getFeedVersion(), ""); - resp.required( "owner", feed.getOwner(), "" ); - resp.required( "asprClassification", feed.getAsprClassification(), "" ); + checker.required( "feedName", feed.getFeedName()); + checker.required( "feedVersion", feed.getFeedVersion()); + checker.required( "owner", feed.getOwner()); + checker.required( "asprClassification", feed.getAsprClassification()); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } FeedService feedService = new FeedService(); - Feed nfeed = feedService.getFeedByName( feed.getFeedName(), feed.getFeedVersion(), resp.getErr() ); + Feed nfeed = feedService.getFeedByName( feed.getFeedName(), feed.getFeedVersion(), apiError); if ( nfeed == null ) { - nfeed = feedService.addFeed( feed, resp.getErr() ); + nfeed = feedService.addFeed(feed, apiError); if ( nfeed != null ) { return responseBuilder.success(nfeed); } else { logger.error( "Unable to create: " + feed.getFeedName() + ":" + feed.getFeedVersion()); - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } } else if ( nfeed.getStatus() == DmaapObject_Status.DELETED ) { feed.setFeedId( nfeed.getFeedId()); - nfeed = feedService.updateFeed(feed, resp.getErr()); + nfeed = feedService.updateFeed(feed, apiError); if ( nfeed != null ) { return responseBuilder.success(nfeed); } else { logger.info( "Unable to update: " + feed.getFeedName() + ":" + feed.getFeedVersion()); - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } } else if ( (useExisting != null) && ("true".compareToIgnoreCase( useExisting ) == 0)) { return responseBuilder.success(nfeed); } - resp.setCode(Status.CONFLICT.getStatusCode()); - return responseBuilder.error(resp.getErr()); + apiError.setCode(Status.CONFLICT.getStatusCode()); + return responseBuilder.error(apiError); } @PUT @@ -149,16 +149,16 @@ public class FeedResource extends BaseLoggingClass { @WebParam(name = "feed") Feed feed) { FeedService feedService = new FeedService(); - ApiService resp = new ApiService(); + ApiError apiError = new ApiError(); try { - resp.required( "feedId", id, ""); + checker.required( "feedId", id); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } - Feed nfeed = feedService.getFeed( id, resp.getErr() ); + Feed nfeed = feedService.getFeed(id, apiError); if ( nfeed == null || nfeed.getStatus() == DmaapObject_Status.DELETED ) { return responseBuilder.notFound(); } @@ -169,13 +169,13 @@ public class FeedResource extends BaseLoggingClass { nfeed.setFeedDescription(feed.getFeedDescription()); nfeed.setFormatUuid(feed.getFormatUuid()); - nfeed = feedService.updateFeed(nfeed, resp.getErr()); + nfeed = feedService.updateFeed(nfeed, apiError); if ( nfeed != null ) { return responseBuilder.success(nfeed); } else { logger.info( "Unable to update: " + feed.getFeedName() + ":" + feed.getFeedVersion()); - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } } @@ -188,25 +188,23 @@ public class FeedResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{id}") - public Response deleteFeed( - @PathParam("id") String id - ){ - ApiService resp = new ApiService(); + public Response deleteFeed(@PathParam("id") String id){ + ApiError apiError = new ApiError(); logger.debug( "Entry: DELETE " + id); FeedService feedService = new FeedService(); - Feed nfeed = feedService.getFeed( id, resp.getErr() ); + Feed nfeed = feedService.getFeed(id, apiError); if ( nfeed == null ) { - resp.setCode(Status.NOT_FOUND.getStatusCode()); - return responseBuilder.error(resp.getErr()); + apiError.setCode(Status.NOT_FOUND.getStatusCode()); + return responseBuilder.error(apiError); } - nfeed = feedService.removeFeed( nfeed, resp.getErr() ); + nfeed = feedService.removeFeed(nfeed, apiError); if ( nfeed == null || nfeed.getStatus() == DmaapObject_Status.DELETED ) { return responseBuilder.success(Status.NO_CONTENT.getStatusCode(), null); } logger.info( "Unable to delete: " + id + ":" + nfeed.getFeedVersion()); - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } @GET @@ -218,17 +216,45 @@ public class FeedResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{id}") - public Response getFeed( - @PathParam("id") String id - ) { - ApiService resp = new ApiService(); + public Response getFeed(@PathParam("id") String id) { + ApiError apiError = new ApiError(); FeedService feedService = new FeedService(); - Feed nfeed = feedService.getFeed( id, resp.getErr() ); + Feed nfeed = feedService.getFeed(id, apiError); if ( nfeed == null ) { - resp.setCode(Status.NOT_FOUND.getStatusCode()); - return responseBuilder.error(resp.getErr()); + apiError.setCode(Status.NOT_FOUND.getStatusCode()); + return responseBuilder.error(apiError); } return responseBuilder.success(nfeed); } + + @PUT + @ApiOperation( value = "sync feeds to existing DR", + notes = "When Bus Controller is deployed after DR, then it is possible" + + "that DR has previous provisioning data that needs to be imported" + + "into Bus Controller.", + response = Feed.class ) + @ApiResponses( value = { + @ApiResponse( code = 200, message = "Success", response = Feed.class), + @ApiResponse( code = 400, message = "Error", response = ApiError.class ) + }) + @Path( "/sync") + public Response syncFeeds (@QueryParam("hard") String hardParam) { + ApiError error = new ApiError(); + + FeedService feedService = new FeedService(); + boolean hard = false; + if ( hardParam != null && hardParam.equalsIgnoreCase("true")) { + hard = true; + } + feedService.sync( hard, error ); + if ( error.is2xx()) { + List<Feed> nfeeds = feedService.getAllFeeds(); + GenericEntity<List<Feed>> list = new GenericEntity<List<Feed>>(nfeeds) { + }; + return responseBuilder.success(list); + } + return responseBuilder.error(error); + } + } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java index a67ac8f..6df8ef6 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java @@ -45,7 +45,6 @@ import org.onap.dmaap.dbcapi.model.ApiError; import org.onap.dmaap.dbcapi.model.MR_Client; import org.onap.dmaap.dbcapi.model.MR_Cluster; import org.onap.dmaap.dbcapi.model.Topic; -import org.onap.dmaap.dbcapi.service.ApiService; import org.onap.dmaap.dbcapi.service.MR_ClientService; import org.onap.dmaap.dbcapi.service.MR_ClusterService; import org.onap.dmaap.dbcapi.service.TopicService; @@ -62,6 +61,7 @@ public class MR_ClientResource extends BaseLoggingClass { private MR_ClientService mr_clientService = new MR_ClientService(); private ResponseBuilder responseBuilder = new ResponseBuilder(); + private RequiredChecker checker = new RequiredChecker(); @GET @ApiOperation( value = "return MR_Client details", @@ -90,58 +90,57 @@ public class MR_ClientResource extends BaseLoggingClass { @ApiResponse( code = 200, message = "Success", response = MR_Client.class), @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) - public Response addMr_Client( - MR_Client client) { - ApiService resp = new ApiService(); + public Response addMr_Client(MR_Client client) { + ApiError apiError = new ApiError(); try { - resp.required( "fqtn", client.getFqtn(), ""); - resp.required( "dcaeLocationName", client.getDcaeLocationName(), ""); + checker.required( "fqtn", client.getFqtn()); + checker.required( "dcaeLocationName", client.getDcaeLocationName()); String s = client.getClientRole(); if ( s == null ) { s = client.getClientIdentity(); } - resp.required( "clientRole or clientIdentity", s, "" ); - resp.required( "action", client.getAction(), ""); + checker.required( "clientRole or clientIdentity", s); + checker.required( "action", client.getAction()); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } MR_ClusterService clusters = new MR_ClusterService(); - MR_Cluster cluster = clusters.getMr_Cluster(client.getDcaeLocationName(), resp.getErr()); + MR_Cluster cluster = clusters.getMr_Cluster(client.getDcaeLocationName(), apiError); if ( cluster == null ) { - resp.setCode(Status.BAD_REQUEST.getStatusCode()); - resp.setMessage( "MR_Cluster alias not found for dcaeLocation: " + client.getDcaeLocationName()); - resp.setFields("dcaeLocationName"); - logger.warn( resp.toString() ); - return responseBuilder.error(resp.getErr()); + apiError.setCode(Status.BAD_REQUEST.getStatusCode()); + apiError.setMessage( "MR_Cluster alias not found for dcaeLocation: " + client.getDcaeLocationName()); + apiError.setFields("dcaeLocationName"); + logger.warn(apiError.toString()); + return responseBuilder.error(apiError); } String url = cluster.getFqdn(); if ( url == null || url.isEmpty() ) { - resp.setCode(Status.BAD_REQUEST.getStatusCode()); - resp.setMessage("FQDN not set for dcaeLocation " + client.getDcaeLocationName() ); - resp.setFields("fqdn"); - logger.warn( resp.toString() ); - return responseBuilder.error(resp.getErr()); + apiError.setCode(Status.BAD_REQUEST.getStatusCode()); + apiError.setMessage("FQDN not set for dcaeLocation " + client.getDcaeLocationName() ); + apiError.setFields("fqdn"); + logger.warn(apiError.toString()); + return responseBuilder.error(apiError); } TopicService topics = new TopicService(); - Topic t = topics.getTopic(client.getFqtn(), resp.getErr() ); + Topic t = topics.getTopic(client.getFqtn(), apiError); if ( t == null ) { - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } - MR_Client nClient = mr_clientService.addMr_Client(client, t, resp.getErr()); - if ( resp.getErr().is2xx()) { - t = topics.getTopic(client.getFqtn(), resp.getErr()); - topics.checkForBridge(t, resp.getErr()); + MR_Client nClient = mr_clientService.addMr_Client(client, t, apiError); + if (apiError.is2xx()) { + t = topics.getTopic(client.getFqtn(), apiError); + topics.checkForBridge(t, apiError); return responseBuilder.success(nClient); } else { - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } } @@ -154,30 +153,27 @@ public class MR_ClientResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{clientId}") - public Response updateMr_Client( - @PathParam("clientId") String clientId, - MR_Client client - ) { - ApiService resp = new ApiService(); + public Response updateMr_Client(@PathParam("clientId") String clientId, MR_Client client) { + ApiError apiError = new ApiError(); try { - resp.required( "fqtn", client.getFqtn(), ""); - resp.required( "dcaeLocationName", client.getDcaeLocationName(), ""); - resp.required( "clientRole", client.getClientRole(), "" ); - resp.required( "action", client.getAction(), ""); + checker.required( "fqtn", client.getFqtn()); + checker.required( "dcaeLocationName", client.getDcaeLocationName()); + checker.required( "clientRole", client.getClientRole()); + checker.required( "action", client.getAction()); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } client.setMrClientId(clientId); - MR_Client nClient = mr_clientService.updateMr_Client(client, resp.getErr() ); - if ( resp.getErr().is2xx()) { + MR_Client nClient = mr_clientService.updateMr_Client(client, apiError); + if (apiError.is2xx()) { return Response.ok(nClient) .build(); } - return Response.status(resp.getErr().getCode()) - .entity( resp.getErr() ) + return Response.status(apiError.getCode()) + .entity(apiError) .build(); } @@ -190,23 +186,21 @@ public class MR_ClientResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{subId}") - public Response deleteMr_Client( - @PathParam("subId") String id - ){ - ApiService resp = new ApiService(); + public Response deleteMr_Client(@PathParam("subId") String id){ + ApiError apiError = new ApiError(); try { - resp.required( "clientId", id, ""); + checker.required( "clientId", id); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } - mr_clientService.removeMr_Client(id, true, resp.getErr() ); - if ( resp.getErr().is2xx()) { + mr_clientService.removeMr_Client(id, true, apiError); + if (apiError.is2xx()) { return responseBuilder.success(NO_CONTENT.getStatusCode(), null); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } @GET @@ -218,21 +212,19 @@ public class MR_ClientResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{subId}") - public Response test( - @PathParam("subId") String id - ) { - ApiService resp = new ApiService(); + public Response test(@PathParam("subId") String id) { + ApiError apiError = new ApiError(); try { - resp.required( "clientId", id, ""); + checker.required( "clientId", id); } catch ( RequiredFieldException rfe ) { - logger.debug( resp.toString() ); - return responseBuilder.error(resp.getErr()); + logger.debug( rfe.getApiError().toString() ); + return responseBuilder.error(rfe.getApiError()); } - MR_Client nClient = mr_clientService.getMr_Client( id, resp.getErr() ); - if ( resp.getErr().is2xx()) { + MR_Client nClient = mr_clientService.getMr_Client(id, apiError); + if (apiError.is2xx()) { return responseBuilder.success(nClient); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResource.java index 5d2d379..0a361ff 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResource.java @@ -43,7 +43,6 @@ import javax.ws.rs.core.Response.Status; import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; import org.onap.dmaap.dbcapi.model.ApiError; import org.onap.dmaap.dbcapi.model.MR_Cluster; -import org.onap.dmaap.dbcapi.service.ApiService; import org.onap.dmaap.dbcapi.service.MR_ClusterService; @@ -56,6 +55,7 @@ public class MR_ClusterResource extends BaseLoggingClass { private MR_ClusterService mr_clusterService = new MR_ClusterService(); private ResponseBuilder responseBuilder = new ResponseBuilder(); + private RequiredChecker checker = new RequiredChecker(); @GET @ApiOperation( value = "return MR_Cluster details", @@ -81,21 +81,20 @@ public class MR_ClusterResource extends BaseLoggingClass { @ApiResponse( code = 200, message = "Success", response = MR_Cluster.class), @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) - public Response addMr_Cluster( - MR_Cluster cluster) { - ApiService resp = new ApiService(); + public Response addMr_Cluster(MR_Cluster cluster) { + ApiError apiError = new ApiError(); try { - resp.required( "dcaeLocationName", cluster.getDcaeLocationName(), "" ); - resp.required( "fqdn", cluster.getFqdn(), "" ); + checker.required( "dcaeLocationName", cluster.getDcaeLocationName()); + checker.required( "fqdn", cluster.getFqdn()); } catch( RequiredFieldException rfe ) { - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(rfe.getApiError()); } - MR_Cluster mrc = mr_clusterService.addMr_Cluster(cluster, resp.getErr() ); + MR_Cluster mrc = mr_clusterService.addMr_Cluster(cluster, apiError); if ( mrc != null && mrc.isStatusValid() ) { return responseBuilder.success(Status.CREATED.getStatusCode(), mrc); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } @@ -108,24 +107,21 @@ public class MR_ClusterResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{clusterId}") - public Response updateMr_Cluster( - @PathParam("clusterId") String clusterId, - MR_Cluster cluster - ) { - ApiService resp = new ApiService(); + public Response updateMr_Cluster(@PathParam("clusterId") String clusterId, MR_Cluster cluster) { + ApiError apiError = new ApiError(); try { - resp.required( "fqdn", clusterId, "" ); - resp.required( "dcaeLocationName", cluster.getDcaeLocationName(), "" ); + checker.required( "fqdn", clusterId); + checker.required( "dcaeLocationName", cluster.getDcaeLocationName()); } catch( RequiredFieldException rfe ) { - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(rfe.getApiError()); } cluster.setDcaeLocationName(clusterId); - MR_Cluster mrc = mr_clusterService.updateMr_Cluster(cluster, resp.getErr() ); + MR_Cluster mrc = mr_clusterService.updateMr_Cluster(cluster, apiError); if ( mrc != null && mrc.isStatusValid() ) { return responseBuilder.success(Status.CREATED.getStatusCode(), mrc); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } @DELETE @@ -137,21 +133,19 @@ public class MR_ClusterResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{clusterId}") - public Response deleteMr_Cluster( - @PathParam("clusterId") String id - ){ - ApiService resp = new ApiService(); + public Response deleteMr_Cluster(@PathParam("clusterId") String id){ + ApiError apiError = new ApiError(); try { - resp.required( "fqdn", id, "" ); + checker.required( "fqdn", id); } catch( RequiredFieldException rfe ) { - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(rfe.getApiError()); } - mr_clusterService.removeMr_Cluster(id, resp.getErr() ); - if ( resp.getErr().is2xx()) { + mr_clusterService.removeMr_Cluster(id, apiError); + if (apiError.is2xx()) { return responseBuilder.success(Status.NO_CONTENT.getStatusCode(), null); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } @GET @@ -163,20 +157,18 @@ public class MR_ClusterResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{clusterId}") - public Response getMR_Cluster( - @PathParam("clusterId") String id - ) { - ApiService resp = new ApiService(); + public Response getMR_Cluster(@PathParam("clusterId") String id) { + ApiError apiError = new ApiError(); try { - resp.required( "dcaeLocationName", id, "" ); + checker.required( "dcaeLocationName", id); } catch( RequiredFieldException rfe ) { - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(rfe.getApiError()); } - MR_Cluster mrc = mr_clusterService.getMr_Cluster( id, resp.getErr() ); + MR_Cluster mrc = mr_clusterService.getMr_Cluster(id, apiError); if ( mrc != null && mrc.isStatusValid() ) { return responseBuilder.success(Status.CREATED.getStatusCode(), mrc); } - return responseBuilder.error(resp.getErr()); + return responseBuilder.error(apiError); } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/RequestTimeLogFilter.java b/src/main/java/org/onap/dmaap/dbcapi/resources/RequestTimeLogFilter.java new file mode 100644 index 0000000..b2b98b6 --- /dev/null +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/RequestTimeLogFilter.java @@ -0,0 +1,55 @@ +/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dmaap.dbcapi.resources;
+
+import com.att.eelf.configuration.EELFLogger;
+import java.time.Clock;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+
+public class RequestTimeLogFilter extends BaseLoggingClass implements ContainerRequestFilter, ContainerResponseFilter {
+
+ private final EELFLogger log;
+ private Clock clock;
+
+ public RequestTimeLogFilter() {
+ this(auditLogger, Clock.systemDefaultZone());
+ }
+
+ RequestTimeLogFilter(EELFLogger logger, Clock clock) {
+ this.log = logger;
+ this.clock = clock;
+ }
+
+ @Override
+ public void filter(ContainerRequestContext requestContext) {
+ requestContext.setProperty("start", clock.millis());
+ }
+
+ @Override
+ public void filter(ContainerRequestContext requestContext, ContainerResponseContext containerResponseContext) {
+ long startTime = (long) requestContext.getProperty("start");
+ long elapsedTime = clock.millis() - startTime;
+ log.info("Request took {} ms", elapsedTime);
+ }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/RequiredChecker.java b/src/main/java/org/onap/dmaap/dbcapi/resources/RequiredChecker.java new file mode 100644 index 0000000..36f0215 --- /dev/null +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/RequiredChecker.java @@ -0,0 +1,53 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dmaap.dbcapi.resources; + +import org.onap.dmaap.dbcapi.model.ApiError; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; + +public class RequiredChecker { + + public void required(String name, Object val) throws RequiredFieldException { + if (val == null) { + throw new RequiredFieldException(new ApiError(BAD_REQUEST.getStatusCode(), + "missing required field", name)); + } + } + + public void required(String name, String val, String expr) throws RequiredFieldException { + + required(name, val); + + if (expr != null && !expr.isEmpty()) { + Pattern pattern = Pattern.compile(expr); + Matcher matcher = pattern.matcher(val); + if (!matcher.find()) { + throw new RequiredFieldException(new ApiError(BAD_REQUEST.getStatusCode(), + "value '" + val + "' violates regexp check '" + expr + "'", name)); + } + } + } + +} diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/RequiredFieldException.java b/src/main/java/org/onap/dmaap/dbcapi/resources/RequiredFieldException.java index 74af356..2968d18 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/RequiredFieldException.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/RequiredFieldException.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,11 +20,27 @@ package org.onap.dmaap.dbcapi.resources; +import org.onap.dmaap.dbcapi.model.ApiError; + public class RequiredFieldException extends Exception { - /** - * - */ - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; + + private final ApiError apiError; + + public RequiredFieldException(ApiError apiError) { + super(); + this.apiError = apiError; + } + + public ApiError getApiError() { + return apiError; + } + @Override + public String toString() { + return "RequiredFieldException{" + + "apiError=" + apiError + + '}'; + } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java index 4f442c9..3206cf7 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java +++ b/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java @@ -46,7 +46,6 @@ import org.onap.dmaap.dbcapi.model.ApiError; import org.onap.dmaap.dbcapi.model.ReplicationType; import org.onap.dmaap.dbcapi.model.FqtnType; import org.onap.dmaap.dbcapi.model.Topic; -import org.onap.dmaap.dbcapi.service.ApiService; import org.onap.dmaap.dbcapi.service.TopicService; import org.onap.dmaap.dbcapi.util.DmaapConfig; @@ -63,6 +62,7 @@ public class TopicResource extends BaseLoggingClass { private static String defaultReplicationCount; private TopicService mr_topicService = new TopicService(); private ResponseBuilder responseBuilder = new ResponseBuilder(); + private RequiredChecker checker = new RequiredChecker(); public TopicResource() { DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig(); @@ -101,20 +101,17 @@ public class TopicResource extends BaseLoggingClass { @ApiResponse( code = 200, message = "Success", response = Topic.class), @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) - public Response addTopic( - Topic topic, - @QueryParam("useExisting") String useExisting - ) { + public Response addTopic(Topic topic, @QueryParam("useExisting") String useExisting) { logger.info( "addTopic request: " + topic + " useExisting=" + useExisting ); - ApiService check = new ApiService(); + ApiError apiError = new ApiError(); try { - check.required( "topicName", topic.getTopicName(), "^\\S+$" ); //no white space allowed in topicName - check.required( "topicDescription", topic.getTopicDescription(), "" ); - check.required( "owner", topic.getOwner(), "" ); + checker.required( "topicName", topic.getTopicName(), "^\\S+$" ); //no white space allowed in topicName + checker.required( "topicDescription", topic.getTopicDescription()); + checker.required( "owner", topic.getOwner()); } catch( RequiredFieldException rfe ) { - logger.error("Error", rfe); - return responseBuilder.error(check.getErr()); + logger.error("Error", rfe.getApiError()); + return responseBuilder.error(rfe.getApiError()); } ReplicationType t = topic.getReplicationCase(); @@ -140,11 +137,11 @@ public class TopicResource extends BaseLoggingClass { flag = "true".compareToIgnoreCase( useExisting ) == 0; } - Topic mrc = mr_topicService.addTopic(topic, check.getErr(), flag); - if ( mrc != null && check.getErr().is2xx() ) { + Topic mrc = mr_topicService.addTopic(topic, apiError, flag); + if ( mrc != null && apiError.is2xx() ) { return responseBuilder.success(CREATED.getStatusCode(), mrc); } - return responseBuilder.error(check.getErr()); + return responseBuilder.error(apiError); } @PUT @@ -156,15 +153,13 @@ public class TopicResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{topicId}") - public Response updateTopic( - @PathParam("topicId") String topicId - ) { - ApiService check = new ApiService(); + public Response updateTopic(@PathParam("topicId") String topicId) { + ApiError apiError = new ApiError(); - check.setCode(Status.BAD_REQUEST.getStatusCode()); - check.setMessage( "Method /PUT not supported for /topics"); + apiError.setCode(Status.BAD_REQUEST.getStatusCode()); + apiError.setMessage( "Method /PUT not supported for /topics"); - return responseBuilder.error(check.getErr()); + return responseBuilder.error(apiError); } @DELETE @@ -176,23 +171,21 @@ public class TopicResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{topicId}") - public Response deleteTopic( - @PathParam("topicId") String id - ){ - ApiService check = new ApiService(); + public Response deleteTopic(@PathParam("topicId") String id){ + ApiError apiError = new ApiError(); try { - check.required( "fqtn", id, "" ); + checker.required( "fqtn", id); } catch( RequiredFieldException rfe ) { - logger.error("Error", rfe); - return responseBuilder.error(check.getErr()); + logger.error("Error", rfe.getApiError()); + return responseBuilder.error(rfe.getApiError()); } - mr_topicService.removeTopic(id, check.getErr()); - if ( check.getErr().is2xx()) { + mr_topicService.removeTopic(id, apiError); + if (apiError.is2xx()) { return responseBuilder.success(Status.NO_CONTENT.getStatusCode(), null); } - return responseBuilder.error(check.getErr()); + return responseBuilder.error(apiError); } @@ -205,21 +198,19 @@ public class TopicResource extends BaseLoggingClass { @ApiResponse( code = 400, message = "Error", response = ApiError.class ) }) @Path("/{topicId}") - public Response getTopic( - @PathParam("topicId") String id - ) { + public Response getTopic(@PathParam("topicId") String id) { logger.info("Entry: /GET " + id); - ApiService check = new ApiService(); + ApiError apiError = new ApiError(); try { - check.required( "topicName", id, "^\\S+$" ); //no white space allowed in topicName + checker.required( "topicName", id, "^\\S+$" ); //no white space allowed in topicName } catch( RequiredFieldException rfe ) { - logger.error("Error", rfe); - return responseBuilder.error(check.getErr()); + logger.error("Error", rfe.getApiError()); + return responseBuilder.error(rfe.getApiError()); } - Topic mrc = mr_topicService.getTopic( id, check.getErr() ); + Topic mrc = mr_topicService.getTopic(id, apiError); if ( mrc == null ) { - return responseBuilder.error(check.getErr()); + return responseBuilder.error(apiError); } return responseBuilder.success(mrc); } diff --git a/src/main/java/org/onap/dmaap/dbcapi/server/ApplicationConfig.java b/src/main/java/org/onap/dmaap/dbcapi/server/ApplicationConfig.java index 2283ea2..2244b73 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/server/ApplicationConfig.java +++ b/src/main/java/org/onap/dmaap/dbcapi/server/ApplicationConfig.java @@ -20,8 +20,8 @@ package org.onap.dmaap.dbcapi.server; import org.glassfish.jersey.server.ResourceConfig; - - +import org.onap.dmaap.dbcapi.resources.RequestTimeLogFilter; +import org.onap.dmaap.dbcapi.resources.AuthorizationFilter; public class ApplicationConfig extends ResourceConfig { @@ -30,7 +30,8 @@ public class ApplicationConfig extends ResourceConfig { */ public ApplicationConfig() { - register(org.onap.dmaap.dbcapi.resources.AuthorizationFilter.class); + register(AuthorizationFilter.class). + register(RequestTimeLogFilter.class); } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/server/JettyServer.java b/src/main/java/org/onap/dmaap/dbcapi/server/JettyServer.java index 4b578b4..7457ce9 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/server/JettyServer.java +++ b/src/main/java/org/onap/dmaap/dbcapi/server/JettyServer.java @@ -22,7 +22,8 @@ package org.onap.dmaap.dbcapi.server; - +import com.google.common.collect.Sets; +import javax.servlet.DispatcherType; import org.eclipse.jetty.server.*; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -31,6 +32,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; import java.util.Properties; + /** * A Jetty server which supports: * - http and https (simultaneously for dev env) @@ -38,48 +40,47 @@ import java.util.Properties; * - static html pages (for documentation). */ public class JettyServer extends BaseLoggingClass { - private Server server; + private Server server; - public Server getServer() { - return server; - } - public JettyServer( Properties params ) throws Exception { + public Server getServer() { + return server; + } + + public JettyServer(Properties params) throws Exception { server = new Server(); - int httpPort = Integer.valueOf(params.getProperty("IntHttpPort", "80" )); - int sslPort = Integer.valueOf(params.getProperty("IntHttpsPort", "443" )); - boolean allowHttp = Boolean.valueOf(params.getProperty("HttpAllowed", "false")); - serverLogger.info( "port params: http=" + httpPort + " https=" + sslPort ); - serverLogger.info( "allowHttp=" + allowHttp ); - - // HTTP Server - HttpConfiguration http_config = new HttpConfiguration(); - http_config.setSecureScheme("https"); - http_config.setSecurePort(sslPort); - http_config.setOutputBufferSize(32768); - - - - try(ServerConnector httpConnector = new ServerConnector(server, new HttpConnectionFactory(http_config))) { - httpConnector.setPort(httpPort); - httpConnector.setIdleTimeout(30000); - - - // HTTPS Server - - HttpConfiguration https_config = new HttpConfiguration(http_config); - https_config.addCustomizer(new SecureRequestCustomizer()); - SslContextFactory sslContextFactory = new SslContextFactory(); - - setUpKeystore(params, sslContextFactory); - setUpTrustStore(params, sslContextFactory); - - if (sslPort != 0) { - try(ServerConnector sslConnector = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory, "http/1.1"), - new HttpConnectionFactory(https_config))) { + int httpPort = Integer.valueOf(params.getProperty("IntHttpPort", "80")); + int sslPort = Integer.valueOf(params.getProperty("IntHttpsPort", "443")); + boolean allowHttp = Boolean.valueOf(params.getProperty("HttpAllowed", "false")); + serverLogger.info("port params: http=" + httpPort + " https=" + sslPort); + serverLogger.info("allowHttp=" + allowHttp); + + // HTTP Server + HttpConfiguration http_config = new HttpConfiguration(); + http_config.setSecureScheme("https"); + http_config.setSecurePort(sslPort); + http_config.setOutputBufferSize(32768); + + try (ServerConnector httpConnector = new ServerConnector(server, new HttpConnectionFactory(http_config))) { + httpConnector.setPort(httpPort); + httpConnector.setIdleTimeout(30000); + + // HTTPS Server + + HttpConfiguration https_config = new HttpConfiguration(http_config); + https_config.addCustomizer(new SecureRequestCustomizer()); + SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.setWantClientAuth(true); + + setUpKeystore(params, sslContextFactory); + setUpTrustStore(params, sslContextFactory); + + if (sslPort != 0) { + try (ServerConnector sslConnector = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, "http/1.1"), + new HttpConnectionFactory(https_config))) { sslConnector.setPort(sslPort); if (allowHttp) { logger.info("Starting httpConnector on port " + httpPort); @@ -91,61 +92,71 @@ public class JettyServer extends BaseLoggingClass { server.setConnectors(new Connector[]{sslConnector}); } } - } else { - serverLogger.info("NOT starting sslConnector on port " + sslPort + " for https"); - if (allowHttp) { - serverLogger.info("Starting httpConnector on port " + httpPort); - server.setConnectors(new Connector[]{httpConnector}); - } - } - } + } else { + serverLogger.info("NOT starting sslConnector on port " + sslPort + " for https"); + if (allowHttp) { + serverLogger.info("Starting httpConnector on port " + httpPort); + server.setConnectors(new Connector[]{httpConnector}); + } + } + } // Set context for servlet. This is shared for http and https - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.setContextPath("/"); - server.setHandler( context ); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + server.setHandler(context); - ServletHolder jerseyServlet = context.addServlet( org.glassfish.jersey.servlet.ServletContainer.class, "/webapi/*"); + ServletHolder jerseyServlet = context + .addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/webapi/*"); jerseyServlet.setInitOrder(1); - jerseyServlet.setInitParameter("jersey.config.server.provider.packages", "org.onap.dmaap.dbcapi.resources" ); - jerseyServlet.setInitParameter("javax.ws.rs.Application", "org.onap.dmaap.dbcapi.server.ApplicationConfig" ); - + jerseyServlet.setInitParameter("jersey.config.server.provider.packages", "org.onap.dmaap.dbcapi.resources"); + jerseyServlet.setInitParameter("javax.ws.rs.Application", "org.onap.dmaap.dbcapi.server.ApplicationConfig"); + // also serve up some static pages... - ServletHolder staticServlet = context.addServlet(DefaultServlet.class,"/*"); - staticServlet.setInitParameter("resourceBase","www"); - staticServlet.setInitParameter("pathInfoOnly","true"); + ServletHolder staticServlet = context.addServlet(DefaultServlet.class, "/*"); + staticServlet.setInitParameter("resourceBase", "www"); + staticServlet.setInitParameter("pathInfoOnly", "true"); + + registerAuthFilters(context); try { serverLogger.info("Starting jetty server"); - String unit_test = params.getProperty("UnitTest", "No"); + String unit_test = params.getProperty("UnitTest", "No"); serverLogger.info("UnitTest=" + unit_test); - if ( unit_test.equals( "No" ) ) { - server.start(); - server.dumpStdErr(); - server.join(); - } - } catch ( Exception e ) { - errorLogger.error( "Exception " + e ); + if (unit_test.equals("No")) { + server.start(); + server.dumpStdErr(); + server.join(); + } + } catch (Exception e) { + errorLogger.error("Exception " + e); } finally { - server.destroy(); + server.destroy(); } - + + } + + private void registerAuthFilters(ServletContextHandler context) { + context.addFilter("org.onap.dmaap.dbcapi.resources.AAFAuthenticationFilter", "/webapi/*", + Sets.newEnumSet(Sets.newHashSet(DispatcherType.FORWARD, DispatcherType.REQUEST), DispatcherType.class)); + context.addFilter("org.onap.dmaap.dbcapi.resources.AAFAuthorizationFilter", "/webapi/*", + Sets.newEnumSet(Sets.newHashSet(DispatcherType.FORWARD, DispatcherType.REQUEST), DispatcherType.class)); } - private void setUpKeystore(Properties params, SslContextFactory sslContextFactory) { - String keystore = params.getProperty("KeyStoreFile", "etc/keystore"); - logger.info("https Server using keystore at " + keystore); - sslContextFactory.setKeyStorePath(keystore); - sslContextFactory.setKeyStorePassword(params.getProperty("KeyStorePassword", "changeit")); - sslContextFactory.setKeyManagerPassword(params.getProperty("KeyPassword", "changeit")); - } - - private void setUpTrustStore(Properties params, SslContextFactory sslContextFactory) { - String truststore = params.getProperty("TrustStoreFile", "etc/org.onap.dmaap-bc.trust.jks"); - logger.info("https Server using truststore at " + truststore); - sslContextFactory.setTrustStorePath(truststore); - sslContextFactory.setTrustStoreType(params.getProperty("TrustStoreType", "jks")); - sslContextFactory.setTrustStorePassword(params.getProperty("TrustStorePassword", "changeit")); - } + private void setUpKeystore(Properties params, SslContextFactory sslContextFactory) { + String keystore = params.getProperty("KeyStoreFile", "etc/keystore"); + logger.info("https Server using keystore at " + keystore); + sslContextFactory.setKeyStorePath(keystore); + sslContextFactory.setKeyStorePassword(params.getProperty("KeyStorePassword", "changeit")); + sslContextFactory.setKeyManagerPassword(params.getProperty("KeyPassword", "changeit")); + } + + private void setUpTrustStore(Properties params, SslContextFactory sslContextFactory) { + String truststore = params.getProperty("TrustStoreFile", "etc/org.onap.dmaap-bc.trust.jks"); + logger.info("https Server using truststore at " + truststore); + sslContextFactory.setTrustStorePath(truststore); + sslContextFactory.setTrustStoreType(params.getProperty("TrustStoreType", "jks")); + sslContextFactory.setTrustStorePassword(params.getProperty("TrustStorePassword", "changeit")); + } } diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java b/src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java index 23f4fef..e1beb28 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java +++ b/src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,261 +20,153 @@ package org.onap.dmaap.dbcapi.service; -import static com.att.eelf.configuration.Configuration.MDC_BEGIN_TIMESTAMP; -import static com.att.eelf.configuration.Configuration.MDC_ELAPSED_TIME; -import static com.att.eelf.configuration.Configuration.MDC_END_TIMESTAMP; import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID; import static com.att.eelf.configuration.Configuration.MDC_PARTNER_NAME; import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.ws.rs.core.Response.Status; import javax.xml.bind.DatatypeConverter; - import org.onap.dmaap.dbcapi.aaf.DmaapPerm; import org.onap.dmaap.dbcapi.authentication.ApiPolicy; import org.onap.dmaap.dbcapi.authentication.AuthenticationErrorException; import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; import org.onap.dmaap.dbcapi.model.ApiError; import org.onap.dmaap.dbcapi.model.Dmaap; -import org.onap.dmaap.dbcapi.resources.RequiredFieldException; import org.onap.dmaap.dbcapi.util.DmaapConfig; import org.onap.dmaap.dbcapi.util.RandomString; import org.slf4j.MDC; public class ApiService extends BaseLoggingClass { - private class StopWatch { - private long clock = 0; - private long elapsed = 0; - - - - public StopWatch() { - clock = 0; - elapsed = 0; - } - - public void reset() { - clock = System.currentTimeMillis(); - elapsed = 0; - } - public void stop() { - Long stopTime = System.currentTimeMillis(); - elapsed += stopTime - clock; - clock = 0; - MDC.put( MDC_END_TIMESTAMP, isoFormatter.format(new Date(stopTime))); - MDC.put( MDC_ELAPSED_TIME, String.valueOf(elapsed)); - } - public void start() { - if ( clock != 0 ) { - //not stopped - return; - } - clock = System.currentTimeMillis(); - MDC.put( MDC_BEGIN_TIMESTAMP, isoFormatter.format(new Date(clock))); - } - private long getElapsed() { - return elapsed; - } - } - - private String apiNamespace; - - private String uri; - private String uriPath; - private String method; - private String authorization; - private String requestId; - private ApiError err; - private StopWatch stopwatch; - private ApiPolicy apiPolicy; - - public static final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; - public final static TimeZone utc = TimeZone.getTimeZone("UTC"); - public final static SimpleDateFormat isoFormatter = new SimpleDateFormat(ISO_FORMAT); - - static { - isoFormatter.setTimeZone(utc); - } - public ApiService() { - - stopwatch = new StopWatch(); - stopwatch.start(); - err = new ApiError(); - requestId = (new RandomString(10)).nextString(); - - if (apiNamespace == null) { - DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig(); - apiNamespace = p.getProperty("ApiNamespace", "org.openecomp.dmaapBC.api"); - logger.info( "config param usePE has been deprecated. Use ApiPermission.Class property instead."); - } - apiPolicy = new ApiPolicy(); - - logger.info( "apiNamespace=" + apiNamespace); - } - - public ApiService setAuth( String auth ) { - this.authorization = auth; - logger.info( "setAuth: authorization={} ", authorization); - return this; - } - private void setServiceName(){ - String svcRequest = new String( this.method + " " + this.uriPath ); - MDC.put(MDC_SERVICE_NAME, svcRequest ); - } - public ApiService setHttpMethod( String httpMethod ) { - this.method = httpMethod; - logger.info( "setHttpMethod: method={} ", method); - setServiceName(); - return this; - } - public ApiService setUriPath( String uriPath ) { - this.uriPath = uriPath; - this.uri = setUriFromPath( uriPath ); - logger.info( "setUriPath: uriPath={} uri={}", uriPath, uri); - setServiceName(); - return this; - } - private String setUriFromPath( String uriPath ) { - int ch = uriPath.indexOf("/"); - if ( ch > 0 ) { - return( (String) uriPath.subSequence(0, ch ) ); - } else { - return uriPath; - } - } - - public ApiError getErr() { - return err; - } - - - public void setErr(ApiError err) { - this.err = err; - } - - - // test for presence of a required field - public void required( String name, Object val, String expr ) throws RequiredFieldException { - err.setCode(0); - if ( val == null ) { - err.setCode(Status.BAD_REQUEST.getStatusCode()); - err.setMessage("missing required field"); - err.setFields( name ); - throw new RequiredFieldException(); - } - if ( expr != null && ! expr.isEmpty() ) { - Pattern pattern = Pattern.compile(expr); - Matcher matcher = pattern.matcher((CharSequence) val); - if ( ! matcher.find() ) { - err.setCode(Status.BAD_REQUEST.getStatusCode()); - err.setMessage( "value '" + val + "' violates regexp check '" + expr + "'"); - err.setFields( name ); - throw new RequiredFieldException(); - } - } - } - - // utility to serialize ApiErr object - public String toString() { - return String.format( "code=%d msg=%s fields=%s", err.getCode(), err.getMessage(), err.getFields() ); - } - - public void setCode(int statusCode) { - err.setCode(statusCode); - } - - - public void setMessage(String string) { - err.setMessage(string); - } - - - public void setFields(String string) { - err.setFields(string); - } - - public void checkAuthorization( String auth, String uriPath, String httpMethod ) throws AuthenticationErrorException, Exception { - authorization = auth; - setUriFromPath( uriPath ); - method = httpMethod; - - checkAuthorization(); - } - - - public void checkAuthorization() throws AuthenticationErrorException, Exception { - - MDC.put(MDC_KEY_REQUEST_ID, requestId); - - logger.info("request: uri={} method={} auth={}", uri, method, authorization ); - - if ( uri == null || uri.isEmpty()) { - String errmsg = "No URI value provided "; - err.setMessage(errmsg); - logger.info( errmsg ); - throw new AuthenticationErrorException( ); - } - if ( method == null || method.isEmpty()) { - String errmsg = "No method value provided "; - err.setMessage(errmsg); - logger.info( errmsg ); - throw new AuthenticationErrorException( ); - } - DmaapService dmaapService = new DmaapService(); - Dmaap dmaap = dmaapService.getDmaap(); - String env = dmaap.getDmaapName(); - - // special case during bootstrap of app when DMaaP environment may not be set. - // this allows us to authorize certain APIs used for initialization during this window. - if ( env == null || env.isEmpty() ) { - env = "boot"; - } - if ( ! apiPolicy.getUseAuthClass() ) return; // skip authorization if not enabled - if ( authorization == null || authorization.isEmpty()) { - String errmsg = "No basic authorization value provided "; - err.setMessage(errmsg); - logger.info( errmsg ); - throw new AuthenticationErrorException( ); - } - String credentials = authorization.substring("Basic".length()).trim(); + private String apiNamespace; + private String uri; + private String uriPath; + private String method; + private String authorization; + private String requestId; + private ApiError err; + private ApiPolicy apiPolicy; + + public ApiService() { + + err = new ApiError(); + requestId = (new RandomString(10)).nextString(); + + if (apiNamespace == null) { + DmaapConfig p = (DmaapConfig) DmaapConfig.getConfig(); + apiNamespace = p.getProperty("ApiNamespace", "org.openecomp.dmaapBC.api"); + logger.info("config param usePE has been deprecated. Use ApiPermission.Class property instead."); + } + apiPolicy = new ApiPolicy(); + + logger.info("apiNamespace=" + apiNamespace); + } + + public ApiService setAuth(String auth) { + this.authorization = auth; + logger.info("setAuth: authorization={} ", authorization); + return this; + } + + private void setServiceName() { + String svcRequest = new String(this.method + " " + this.uriPath); + MDC.put(MDC_SERVICE_NAME, svcRequest); + } + + public ApiService setHttpMethod(String httpMethod) { + this.method = httpMethod; + logger.info("setHttpMethod: method={} ", method); + setServiceName(); + return this; + } + + public ApiService setUriPath(String uriPath) { + this.uriPath = uriPath; + this.uri = setUriFromPath(uriPath); + logger.info("setUriPath: uriPath={} uri={}", uriPath, uri); + setServiceName(); + return this; + } + + private String setUriFromPath(String uriPath) { + int ch = uriPath.indexOf("/"); + if (ch > 0) { + return ((String) uriPath.subSequence(0, ch)); + } else { + return uriPath; + } + } + + public ApiError getErr() { + return err; + } + + public void checkAuthorization() throws Exception { + + MDC.put(MDC_KEY_REQUEST_ID, requestId); + + logger.info("request: uri={} method={} auth={}", uri, method, authorization); + + if (uri == null || uri.isEmpty()) { + String errmsg = "No URI value provided "; + err.setMessage(errmsg); + logger.info(errmsg); + throw new AuthenticationErrorException(); + } + if (method == null || method.isEmpty()) { + String errmsg = "No method value provided "; + err.setMessage(errmsg); + logger.info(errmsg); + throw new AuthenticationErrorException(); + } + DmaapService dmaapService = new DmaapService(); + Dmaap dmaap = dmaapService.getDmaap(); + String env = dmaap.getDmaapName(); + + // special case during bootstrap of app when DMaaP environment may not be set. + // this allows us to authorize certain APIs used for initialization during this window. + if (env == null || env.isEmpty()) { + env = "boot"; + } + if (!apiPolicy.getUseAuthClass()) { + return; // skip authorization if not enabled + } + if (authorization == null || authorization.isEmpty()) { + String errmsg = "No basic authorization value provided "; + err.setMessage(errmsg); + logger.info(errmsg); + throw new AuthenticationErrorException(); + } + String credentials = authorization.substring("Basic".length()).trim(); byte[] decoded = DatatypeConverter.parseBase64Binary(credentials); String decodedString = new String(decoded); String[] actualCredentials = decodedString.split(":"); String ID = actualCredentials[0]; String Password = actualCredentials[1]; MDC.put(MDC_PARTNER_NAME, ID); - try { - - DmaapPerm p = new DmaapPerm( apiNamespace + "." + uri, env, method ); - apiPolicy.check( ID, Password, p); - } catch ( AuthenticationErrorException ae ) { - String errmsg = "User " + ID + " failed authentication/authorization for " + apiNamespace + "." + uriPath + " " + env + " " + method; - logger.info( errmsg ); - err.setMessage(errmsg); - throw ae; - - } - - - } - public String getRequestId() { - return requestId; - } - public ApiService setRequestId(String requestId) { - if ( requestId == null || requestId.isEmpty()) { - this.requestId = (new RandomString(10)).nextString(); - logger.warn( "X-ECOMP-RequestID not set in HTTP Header. Setting RequestId value to: " + this.requestId ); - } else { - this.requestId = requestId; - } - MDC.put(MDC_KEY_REQUEST_ID, this.requestId); - return this; - } + try { + + DmaapPerm p = new DmaapPerm(apiNamespace + "." + uri, env, method); + apiPolicy.check(ID, Password, p); + } catch (AuthenticationErrorException ae) { + String errmsg = + "User " + ID + " failed authentication/authorization for " + apiNamespace + "." + uriPath + " " + env + + " " + method; + logger.info(errmsg); + err.setMessage(errmsg); + throw ae; + + } + } + + public ApiService setRequestId(String requestId) { + if (requestId == null || requestId.isEmpty()) { + this.requestId = (new RandomString(10)).nextString(); + logger.warn("X-ECOMP-RequestID not set in HTTP Header. Setting RequestId value to: " + this.requestId); + } else { + this.requestId = requestId; + } + MDC.put(MDC_KEY_REQUEST_ID, this.requestId); + return this; + } } + diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/DR_NodeService.java b/src/main/java/org/onap/dmaap/dbcapi/service/DR_NodeService.java index b478dca..9181154 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/service/DR_NodeService.java +++ b/src/main/java/org/onap/dmaap/dbcapi/service/DR_NodeService.java @@ -215,11 +215,11 @@ public class DR_NodeService extends BaseLoggingClass { } public DR_Node updateDr_Node( DR_Node node, ApiError apiError ) { - DR_Node old = dr_nodes.get( node ); + DR_Node old = dr_nodes.get( node.getFqdn() ); if ( old == null ) { apiError.setCode(Status.NOT_FOUND.getStatusCode()); apiError.setFields( "fqdn"); - apiError.setMessage( "Node " + node + " does not exist"); + apiError.setMessage( "Node " + node.getFqdn() + " does not exist"); return null; } node.setLastMod(); diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/DR_PubService.java b/src/main/java/org/onap/dmaap/dbcapi/service/DR_PubService.java index 13717da..eb5b514 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/service/DR_PubService.java +++ b/src/main/java/org/onap/dmaap/dbcapi/service/DR_PubService.java @@ -129,7 +129,11 @@ public class DR_PubService extends BaseLoggingClass{ } public DR_Pub removeDr_Pub( String pubId, ApiError err ) { - + return removeDr_Pub( pubId, err, true ); + } + + + public DR_Pub removeDr_Pub( String pubId, ApiError err, boolean hitDR ) { DR_Pub pub = dr_pubs.get( pubId ); if ( pub == null ) { err.setCode(Status.NOT_FOUND.getStatusCode()); diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/DR_SubService.java b/src/main/java/org/onap/dmaap/dbcapi/service/DR_SubService.java index 9d233a5..0a583a0 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/service/DR_SubService.java +++ b/src/main/java/org/onap/dmaap/dbcapi/service/DR_SubService.java @@ -173,6 +173,11 @@ public class DR_SubService extends BaseLoggingClass { } public void removeDr_Sub( String key, ApiError apiError ) { + removeDr_Sub( key, apiError, true ); + return; + } + + public void removeDr_Sub( String key, ApiError apiError, boolean hitDR ) { logger.debug( "enter removeDR_Subs()"); DR_Sub sub = dr_subs.get( key ); @@ -180,11 +185,15 @@ public class DR_SubService extends BaseLoggingClass { apiError.setCode(Status.NOT_FOUND.getStatusCode()); apiError.setFields( "subId"); apiError.setMessage("subId " + key + " not found"); - } else { - DrProvConnection prov = new DrProvConnection(); - prov.makeSubPutConnection( key ); - String resp = prov.doDeleteDr_Sub( sub, apiError ); - logger.debug( "resp=" + resp ); + } else { + if ( hitDR ) { + DrProvConnection prov = new DrProvConnection(); + prov.makeSubPutConnection( key ); + String resp = prov.doDeleteDr_Sub( sub, apiError ); + logger.debug( "resp=" + resp ); + } else { + apiError.setCode(200); + } if ( apiError.is2xx() || unit_test.equals( "Yes" ) ) { dr_subs.remove(key); @@ -209,8 +218,8 @@ public class DR_SubService extends BaseLoggingClass { server, subid, sub.getUsername(), sub.getUserpwd()); String links = String.format( "\"links\": {\"feed\": \"https://dr-prov/feedlog/%s\", \"self\": \"https://dr-prov/sub/%s\", \"log\": \"https://dr-prov/sublog/%s\" }", sub.getFeedId(), - sub.getSubId(), - sub.getSubId() ); + subid, + subid ); ret += links + "}"; logger.info( "DR_SubService:simulateResp=" + ret); diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/FeedService.java b/src/main/java/org/onap/dmaap/dbcapi/service/FeedService.java index de18d95..77d11ab 100644 --- a/src/main/java/org/onap/dmaap/dbcapi/service/FeedService.java +++ b/src/main/java/org/onap/dmaap/dbcapi/service/FeedService.java @@ -25,12 +25,17 @@ package org.onap.dmaap.dbcapi.service; import org.onap.dmaap.dbcapi.util.RandomInteger; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Map; import javax.ws.rs.core.Response.Status; import org.apache.log4j.Logger; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; import org.onap.dmaap.dbcapi.client.DrProvConnection; import org.onap.dmaap.dbcapi.database.DatabaseClass; import org.onap.dmaap.dbcapi.logging.BaseLoggingClass; @@ -38,12 +43,14 @@ import org.onap.dmaap.dbcapi.model.ApiError; import org.onap.dmaap.dbcapi.model.DR_Pub; import org.onap.dmaap.dbcapi.model.DR_Sub; import org.onap.dmaap.dbcapi.model.Feed; +import org.onap.dmaap.dbcapi.model.MR_Client; import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status; import org.onap.dmaap.dbcapi.util.DmaapConfig; public class FeedService extends BaseLoggingClass { private Map<String, Feed> feeds = DatabaseClass.getFeeds(); + private Map<String, DR_Sub> dr_subs = DatabaseClass.getDr_subs(); private DR_PubService pubService = new DR_PubService(); private DR_SubService subService = new DR_SubService(); private DcaeLocationService dcaeLocations = new DcaeLocationService(); @@ -68,6 +75,10 @@ public class FeedService extends BaseLoggingClass { ArrayList<DR_Sub> subs = subService.getDr_SubsByFeedId( f.getFeedId() ); f.setSubs(subs); } + + public List<Feed> getAllFeeds(){ + return getAllFeeds(null, null, null); + } public List<Feed> getAllFeeds( String name, String ver, String match ) { logger.info( "getAllFeeds: name=" + name + " ver=" + ver + " match=" + match); @@ -351,22 +362,30 @@ public class FeedService extends BaseLoggingClass { // 2) Call the DR Delete function. Feed with the same name and version can never be added again // public Feed removeFeed( Feed req, ApiError err ) { + return removeFeed( req, err, true ); + } + + public Feed removeFeed( Feed req, ApiError err, boolean hitDR ) { // strip pubs and subs from feed first no matter what ArrayList<DR_Pub> pubs = pubService.getDr_PubsByFeedId( req.getFeedId() ); for( DR_Pub pub: pubs ) { - pubService.removeDr_Pub(pub.getPubId(), err); + pubService.removeDr_Pub(pub.getPubId(), err, hitDR); if ( ! err.is2xx()) { return req; } } ArrayList<DR_Sub> subs = subService.getDr_SubsByFeedId( req.getFeedId() ); for ( DR_Sub sub: subs ) { - subService.removeDr_Sub(sub.getSubId(), err); + subService.removeDr_Sub(sub.getSubId(), err, hitDR); if ( ! err.is2xx()) { return req; } } + + if ( ! hitDR ) { + return feeds.remove(req.getFeedId()); + } if ( deleteHandling.equalsIgnoreCase("DeleteOnDR")) { DrProvConnection prov = new DrProvConnection(); @@ -415,6 +434,92 @@ public class FeedService extends BaseLoggingClass { } + + + /* + * sync will retrieve current config from DR and add it to the DB + * when hard = true, then first git rid of current DR provisioning data (from the DB) + */ + public void sync( boolean hard, ApiError err ) { + + if ( hard ) { + + ArrayList<Feed> flist = new ArrayList<Feed>(this.getAllFeeds()); + for ( Iterator<Feed> it = flist.iterator(); it.hasNext(); ) { + Feed f = it.next(); + + @SuppressWarnings("unused") + Feed old = removeFeed( f, err, false ); + if (! err.is2xx()) { + return; + } + } + } + + DrProvConnection prov = new DrProvConnection(); + prov.makeDumpConnection(); + String resp = prov.doGetDump( err ); + if (! err.is2xx()) { + return; + } + logger.debug("sync: resp from DR is: " + resp); + + JSONParser parser = new JSONParser(); + JSONObject jsonObj; + try { + jsonObj = (JSONObject) parser.parse( resp ); + } catch ( ParseException pe ) { + logger.error( "Error parsing provisioning data: " + resp ); + err.setCode(500); + return; + } + + int i; + + JSONArray feedsArray = (JSONArray) jsonObj.get( "feeds"); + for( i = 0; i < feedsArray.size(); i++ ) { + JSONObject entry = (JSONObject) feedsArray.get(i); + Feed fnew = new Feed( entry.toJSONString() ); + + logger.info( "fnew status is:" + fnew.getStatus() ); + if ( ! fnew.isStatusValid()) { + err.setCode(500); + err.setMessage( "Unexpected response from DR backend" ); + err.setFields("response"); + return; + } + + if ( ! savePubs( fnew ) ) { + err.setCode(Status.BAD_REQUEST.getStatusCode()); + err.setMessage("Unable to save Pub or Sub objects"); + return; + } + fnew.setFormatUuid(fnew.getFormatUuid()); + fnew.setLastMod(); + feeds.put( fnew.getFeedId(), fnew ); + + } + + JSONArray subArray = (JSONArray) jsonObj.get( "subscriptions"); + for( i = 0; i < subArray.size(); i++ ) { + JSONObject entry = (JSONObject) subArray.get(i); + DR_Sub snew = new DR_Sub( entry.toJSONString() ); + + logger.info( "snew status is:" + snew.getStatus() ); + if ( ! snew.isStatusValid()) { + err.setCode(500); + err.setMessage( "Unexpected response from DR backend" ); + err.setFields("response"); + return; + } + + dr_subs.put( snew.getSubId(), snew ); + + } + err.setCode(200); + return; + + } private String simulateResp( Feed f, String action ){ String server = "localhost"; diff --git a/src/main/java/org/onap/dmaap/dbcapi/util/PermissionBuilder.java b/src/main/java/org/onap/dmaap/dbcapi/util/PermissionBuilder.java new file mode 100644 index 0000000..44c94af --- /dev/null +++ b/src/main/java/org/onap/dmaap/dbcapi/util/PermissionBuilder.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dmaap + * ================================================================================ + * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dmaap.dbcapi.util; + +import javax.servlet.http.HttpServletRequest; +import org.onap.dmaap.dbcapi.model.Dmaap; +import org.onap.dmaap.dbcapi.service.DmaapService; + +public class PermissionBuilder { + + static final String API_NS_PROP = "ApiNamespace"; + static final String DEFAULT_API_NS = "org.onap.dmaap-bc.api"; + static final String BOOT_INSTANCE = "boot"; + private static final String PERM_SEPARATOR = "|"; + private static final String NS_SEPARATOR = "."; + private DmaapConfig dmaapConfig; + private DmaapService dmaapService; + private String instance; + private String apiNamespace; + + public PermissionBuilder(DmaapConfig dmaapConfig, DmaapService dmaapService) { + this.dmaapConfig = dmaapConfig; + this.dmaapService = dmaapService; + initFields(); + } + + public synchronized void updateDmaapInstance() { + if(instance == null || instance.isEmpty() || instance.equalsIgnoreCase(BOOT_INSTANCE)) { + String dmaapName = getDmaapName(); + instance = (dmaapName == null || dmaapName.isEmpty()) ? BOOT_INSTANCE : dmaapName; + } + } + + public String buildPermission(HttpServletRequest httpRequest) { + + StringBuilder sb = new StringBuilder(apiNamespace); + sb.append(NS_SEPARATOR) + .append(getPermissionType(httpRequest.getPathInfo())) + .append(PERM_SEPARATOR) + .append(instance) + .append(PERM_SEPARATOR) + .append(httpRequest.getMethod()); + return sb.toString(); + } + + + private void initFields() { + apiNamespace = dmaapConfig.getProperty(API_NS_PROP, DEFAULT_API_NS); + updateDmaapInstance(); + } + + private String getDmaapName() { + Dmaap dmaap = dmaapService.getDmaap(); + return ( dmaap != null ) ? dmaap.getDmaapName() : BOOT_INSTANCE; + } + + private String getPermissionType(String pathInfo) { + char pathSeparator = '/'; + String relativePath = (pathInfo.charAt(pathInfo.length()-1) == pathSeparator) ? + pathInfo.substring(0,pathInfo.length()-1) : pathInfo; + + String[] pathSlices = relativePath.split(String.valueOf(pathSeparator)); + return pathSlices[pathSlices.length-1]; + } + + String getInstance() { + return instance; + } +} diff --git a/src/test/java/org/onap/dmaap/dbcapi/model/DmaapTest.java b/src/test/java/org/onap/dmaap/dbcapi/model/DmaapTest.java index fb83fe9..c0f3bef 100644 --- a/src/test/java/org/onap/dmaap/dbcapi/model/DmaapTest.java +++ b/src/test/java/org/onap/dmaap/dbcapi/model/DmaapTest.java @@ -19,17 +19,14 @@ */ package org.onap.dmaap.dbcapi.model; -import static org.junit.Assert.*; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import static org.junit.Assert.assertTrue; import org.junit.After; import org.junit.Before; import org.junit.Test; + public class DmaapTest { - String ver, tnr, dn, dpu, lu, bat, nk, ako; + private String ver, tnr, dn, dpu, lu, bat, nk, ako; @Before public void setUp() throws Exception { diff --git a/src/test/java/org/onap/dmaap/dbcapi/model/TopicTest.java b/src/test/java/org/onap/dmaap/dbcapi/model/TopicTest.java index 5180b99..5da3aed 100644 --- a/src/test/java/org/onap/dmaap/dbcapi/model/TopicTest.java +++ b/src/test/java/org/onap/dmaap/dbcapi/model/TopicTest.java @@ -4,6 +4,8 @@ * ================================================================================ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. * ================================================================================ + * Modifications Copyright (c) 2019 IBM + * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -19,62 +21,67 @@ */ package org.onap.dmaap.dbcapi.model; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status; import org.onap.dmaap.dbcapi.testframework.ReflectionHarness; - public class TopicTest { - private static final String fmt = "%24s: %s%n"; - - ReflectionHarness rh = new ReflectionHarness(); - - String f, t, d, e, o; - - @Before - public void setUp() throws Exception { - f = "org.onap.dmaap.interestingTopic"; - t = "interestingTopic"; - d = "A so very interesting topic"; - e = "Yes"; - o = "m12345"; - } - - @After - public void tearDown() throws Exception { - } - - - @Test - public void test1() { - - - rh.reflect( "org.onap.dmaap.dbcapi.model.Topic", "get", null ); - - } - - @Test - public void test2() { - String[] a = { "put", "view" }; - Topic obj = new Topic( f, t, d, e, o ); - - - assertTrue( f.equals( obj.getFqtn() )); - assertTrue( t.equals( obj.getTopicName() )); - assertTrue( d.equals( obj.getTopicDescription() )); - assertTrue( e.equals( obj.getTnxEnabled() )); - assertTrue( o.equals( obj.getOwner() )); - } - - @Test - public void test3() { - - String v = "Validate"; - rh.reflect( "org.onap.dmaap.dbcapi.model.Topic", "set", v ); - } + ReflectionHarness rh = new ReflectionHarness(); + + String f, t, d, e, o; + + @Before + public void setUp() throws Exception { + f = "org.onap.dmaap.interestingTopic"; + t = "interestingTopic"; + d = "A so very interesting topic"; + e = "Yes"; + o = "m12345"; + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test1() { + rh.reflect("org.onap.dmaap.dbcapi.model.Topic", "get", null); + } + + @Test + public void test2() { + Topic obj = new Topic(f, t, d, e, o); + assertTrue(f.equals(obj.getFqtn())); + assertTrue(t.equals(obj.getTopicName())); + assertTrue(d.equals(obj.getTopicDescription())); + assertTrue(e.equals(obj.getTnxEnabled())); + assertTrue(o.equals(obj.getOwner())); + } + + @Test + public void test3() { + String v = "Validate"; + rh.reflect("org.onap.dmaap.dbcapi.model.Topic", "set", v); + } + + @Test + public void getNumClientsHavingMRClientListNull() { + Topic obj = new Topic(f, t, d, e, o); + obj.setClients(null); + assertEquals(0, obj.getNumClients()); + } + + @Test + public void testTopicInitializationWithInvalidJsonString() { + String json = "{\"key\":\"value\""; + Topic obj = new Topic(json); + assertEquals(DmaapObject_Status.INVALID, obj.getStatus()); + } } diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/AAFAuthenticationFilterTest.java b/src/test/java/org/onap/dmaap/dbcapi/resources/AAFAuthenticationFilterTest.java new file mode 100644 index 0000000..d5ae5fd --- /dev/null +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/AAFAuthenticationFilterTest.java @@ -0,0 +1,178 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dmaap + * ================================================================================ + * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dmaap.dbcapi.resources; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; + +import java.io.PrintWriter; +import java.io.StringWriter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.dmaap.dbcapi.util.DmaapConfig; + +@RunWith(MockitoJUnitRunner.class) +public class AAFAuthenticationFilterTest { + + @Spy + private AAFAuthenticationFilter filter; + @Mock + private FilterConfig filterConfig; + @Mock + private CadiFilter cadiFilterMock; + @Mock + private HttpServletRequest servletRequest; + @Mock + private HttpServletResponse servletResponse; + @Mock + private FilterChain filterChain; + @Mock + private DmaapConfig dmaapConfig; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void setUp() throws Exception { + doReturn(dmaapConfig).when(filter).getConfig(); + } + + @Test + public void init_shouldNotInitializeCADI_whenAafIsNotUsed() throws Exception { + //given + doReturn("false").when(dmaapConfig).getProperty(eq(AAFAuthenticationFilter.AAF_AUTHN_FLAG), anyString()); + + //when + filter.init(filterConfig); + + //then + assertFalse(filter.isAafEnabled()); + assertNull(filter.getCadiFilter()); + } + + @Test + public void doFilter_shouldSkipCADI_whenAafIsNotUsed() throws Exception { + //given + doReturn("false").when(dmaapConfig).getProperty(eq(AAFAuthenticationFilter.AAF_AUTHN_FLAG), anyString()); + filter.init(filterConfig); + filter.setCadiFilter(cadiFilterMock); + + //when + filter.doFilter(servletRequest, servletResponse, filterChain); + + //then + verify(filterChain).doFilter(servletRequest,servletResponse); + verifyZeroInteractions(cadiFilterMock,servletRequest,servletResponse); + } + + @Test + public void init_shouldFail_whenAafIsUsed_andCadiPropertiesHasNotBeenSet() throws Exception { + //given + doReturn("true").when(dmaapConfig).getProperty(eq(AAFAuthenticationFilter.AAF_AUTHN_FLAG), anyString()); + doReturn("").when(dmaapConfig).getProperty(AAFAuthenticationFilter.CADI_PROPERTIES); + + //then + thrown.expect(ServletException.class); + thrown.expectMessage("Cannot initialize CADI filter.CADI properties not available."); + + //when + filter.init(filterConfig); + } + + @Test + public void init_shouldInitializeCADI_whenAafIsUsed_andCadiPropertiesSet() throws Exception { + //given + doReturn("true").when(dmaapConfig).getProperty(eq(AAFAuthenticationFilter.AAF_AUTHN_FLAG), anyString()); + doReturn("cadi.properties").when(dmaapConfig).getProperty(AAFAuthenticationFilter.CADI_PROPERTIES); + + //when + filter.init(filterConfig); + + //then + assertTrue(filter.isAafEnabled()); + assertNotNull(filter.getCadiFilter()); + } + + @Test + public void doFilter_shouldUseCADIfilter_andAuthenticateUser_whenAAFisUsed_andUserIsValid() throws Exception{ + //given + initCADIFilter(); + doReturn(200).when(servletResponse).getStatus(); + + //when + filter.doFilter(servletRequest,servletResponse,filterChain); + + //then + verify(cadiFilterMock).doFilter(servletRequest,servletResponse,filterChain); + verify(servletResponse).getStatus(); + verifyNoMoreInteractions(servletResponse); + verifyZeroInteractions(filterChain, servletRequest); + } + + @Test + public void doFilter_shouldUseCADIfilter_andReturnAuthenticationError_whenAAFisUsed_andUserInvalid() throws Exception{ + //given + String errorResponseJson = "{\"code\":401,\"message\":\"invalid or no credentials provided\",\"fields\":\"Authentication\",\"2xx\":false}"; + initCADIFilter(); + doReturn(401).when(servletResponse).getStatus(); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + doReturn(pw).when(servletResponse).getWriter(); + + //when + filter.doFilter(servletRequest,servletResponse,filterChain); + + //then + verify(cadiFilterMock).doFilter(servletRequest,servletResponse,filterChain); + verify(servletResponse).getStatus(); + verify(servletResponse).setContentType("application/json"); + verifyZeroInteractions(filterChain, servletRequest); + assertEquals(errorResponseJson, sw.toString()); + } + + private void initCADIFilter() throws Exception{ + doReturn("true").when(dmaapConfig).getProperty(eq(AAFAuthenticationFilter.AAF_AUTHN_FLAG), anyString()); + doReturn("cadi.properties").when(dmaapConfig).getProperty(AAFAuthenticationFilter.CADI_PROPERTIES); + filter.init(filterConfig); + filter.setCadiFilter(cadiFilterMock); + } + +}
\ No newline at end of file diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/AAFAuthorizationFilterTest.java b/src/test/java/org/onap/dmaap/dbcapi/resources/AAFAuthorizationFilterTest.java new file mode 100644 index 0000000..73794cd --- /dev/null +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/AAFAuthorizationFilterTest.java @@ -0,0 +1,172 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dmaap + * ================================================================================ + * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dmaap.dbcapi.resources; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import java.io.PrintWriter; +import java.io.StringWriter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.dmaap.dbcapi.model.Dmaap; +import org.onap.dmaap.dbcapi.service.DmaapService; +import org.onap.dmaap.dbcapi.util.DmaapConfig; +import org.onap.dmaap.dbcapi.util.PermissionBuilder; +import sun.security.acl.PrincipalImpl; + +@RunWith(MockitoJUnitRunner.class) +public class AAFAuthorizationFilterTest { + + @Spy + private AAFAuthorizationFilter filter; + @Mock + private FilterConfig filterConfig; + @Mock + private HttpServletRequest servletRequest; + @Mock + private HttpServletResponse servletResponse; + @Mock + private FilterChain filterChain; + @Mock + private DmaapConfig dmaapConfig; + @Mock + private PermissionBuilder permissionBuilder; + @Mock + private DmaapService dmaapService; + + @Before + public void setUp() throws Exception { + filter.setPermissionBuilder(permissionBuilder); + doReturn(dmaapConfig).when(filter).getConfig(); + doReturn(dmaapService).when(filter).getDmaapService(); + } + + @Test + public void init_shouldNotInitializePermissionBuilder_whenAAFnotUsed() throws Exception { + //given + filter.setPermissionBuilder(null); + configureAAFUsage(false); + + //when + filter.init(filterConfig); + + //then + assertNull(filter.getPermissionBuilder()); + } + + @Test + public void init_shouldInitializePermissionBuilder_whenAAFisUsed() throws Exception { + //given + filter.setPermissionBuilder(null); + configureAAFUsage(true); + //doReturn(provideEmptyInstance()).when(dmaapService).getDmaap(); + when(dmaapService.getDmaap()).thenReturn(mock(Dmaap.class)); + + //when + filter.init(filterConfig); + + //then + assertNotNull(permissionBuilder); + } + + @Test + public void doFilter_shouldSkipAuthorization_whenAAFnotUsed() throws Exception { + //given + filter.setAafEnabled(false); + + //when + filter.doFilter(servletRequest,servletResponse,filterChain); + + //then + verify(filterChain).doFilter(servletRequest,servletResponse); + verifyNoMoreInteractions(filterChain); + verifyZeroInteractions(permissionBuilder, servletRequest, servletResponse); + } + + @Test + public void doFilter_shouldPass_whenUserHasPermissionToResourceEndpoint() throws Exception { + //given + String user = "johnny"; + String permission = "org.onap.dmaap-bc.api.topics|mr|GET"; + when(permissionBuilder.buildPermission(servletRequest)).thenReturn(permission); + configureServletRequest(permission, user, true); + filter.setAafEnabled(true); + + //when + filter.doFilter(servletRequest,servletResponse,filterChain); + + //then + verify(filterChain).doFilter(servletRequest,servletResponse); + verify(permissionBuilder).updateDmaapInstance(); + verifyZeroInteractions(servletResponse); + } + + @Test + public void doFilter_shouldReturnError_whenUserDontHavePermissionToResourceEndpoint() throws Exception { + //given + String user = "jack"; + String permission = "org.onap.dmaap-bc.api.topics|mr|GET"; + when(permissionBuilder.buildPermission(servletRequest)).thenReturn(permission); + configureServletRequest(permission, user, false); + filter.setAafEnabled(true); + + String errorMsgJson = "{\"code\":403,\"message\":\"User "+user+" does not have permission " + + permission +"\",\"fields\":\"Authorization\",\"2xx\":false}"; + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + when(servletResponse.getWriter()).thenReturn(pw); + + //when + filter.doFilter(servletRequest,servletResponse,filterChain); + + //then + verifyZeroInteractions(filterChain); + verify(permissionBuilder).updateDmaapInstance(); + verify(servletResponse).setStatus(403); + assertEquals(errorMsgJson, sw.toString()); + } + + private void configureServletRequest(String permission, String user, boolean isUserInRole) { + when(servletRequest.getUserPrincipal()).thenReturn(new PrincipalImpl(user)); + when(servletRequest.isUserInRole(permission)).thenReturn(isUserInRole); + } + + private void configureAAFUsage(Boolean isUsed) { + doReturn(isUsed.toString()).when(dmaapConfig).getProperty(eq(AAFAuthorizationFilter.AAF_AUTHZ_FLAG), anyString()); + } +}
\ No newline at end of file diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/DR_NodeResourceTest.java b/src/test/java/org/onap/dmaap/dbcapi/resources/DR_NodeResourceTest.java index 01ef6ae..856a789 100644 --- a/src/test/java/org/onap/dmaap/dbcapi/resources/DR_NodeResourceTest.java +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/DR_NodeResourceTest.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,107 +19,231 @@ */ package org.onap.dmaap.dbcapi.resources; -import org.onap.dmaap.dbcapi.model.*; -import org.onap.dmaap.dbcapi.service.*; -import org.onap.dmaap.dbcapi.testframework.DmaapObjectFactory; - -import static org.junit.Assert.*; - -import org.junit.After; +import org.glassfish.jersey.server.ResourceConfig; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; -import java.util.*; -import java.sql.*; +import org.onap.dmaap.dbcapi.database.DatabaseClass; +import org.onap.dmaap.dbcapi.model.ApiError; +import org.onap.dmaap.dbcapi.model.DR_Node; +import org.onap.dmaap.dbcapi.testframework.DmaapObjectFactory; -import org.glassfish.jersey.test.JerseyTest; -import org.glassfish.jersey.server.ResourceConfig; import javax.ws.rs.client.Entity; -import javax.ws.rs.core.Application; import javax.ws.rs.core.Response; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.Path; -import javax.ws.rs.GET; - - -public class DR_NodeResourceTest extends JerseyTest { - - static DmaapObjectFactory factory = new DmaapObjectFactory(); - static String entry_path = "dr_nodes"; - - @Override - protected Application configure() { - return new ResourceConfig( DR_NodeResource.class ); - } - - private static final String fmt = "%24s: %s%n"; - - - -/* may conflict with test framework! - @Before - public void preTest() throws Exception { - } - - @After - public void tearDown() throws Exception { - } -*/ - - - @Test - public void GetTest() { - Response resp = target( entry_path ).request().get( Response.class ); - System.out.println( "GET " + entry_path + " resp=" + resp.getStatus() ); - - assertTrue( resp.getStatus() == 200 ); - } - @Test - public void PostTest() { - DR_Node node = factory.genDR_Node( "central" ); - Entity<DR_Node> reqEntity = Entity.entity( node, MediaType.APPLICATION_JSON ); - Response resp = target( entry_path ).request().post( reqEntity, Response.class ); - System.out.println( "POST " + entry_path + " resp=" + resp.getStatus() + " " + resp.readEntity( String.class ) ); - assertTrue( resp.getStatus() == 200 ); - } - - @Test - public void PutTest() { - -/* - try { - DcaeLocation loc = factory.genDcaeLocation( "central" ); - Entity<DcaeLocation> reqEntity = Entity.entity( loc, MediaType.APPLICATION_JSON ); - Response resp = target( "dcaeLocations").request().post( reqEntity, Response.class ); - System.out.println( "POST dcaeLocation resp=" + resp.getStatus() + " " + resp.readEntity( String.class )); - assertTrue( resp.getStatus() == 201 ); - } catch (Exception e ) { - } -*/ - - DR_Node node = factory.genDR_Node( "central" ); - Entity<DR_Node> reqEntity = Entity.entity( node, MediaType.APPLICATION_JSON ); - Response resp = target( entry_path ).request().post( reqEntity, Response.class ); - - // first, add it - System.out.println( "POST " + entry_path + " resp=" + resp.getStatus() + " " + resp.readEntity( String.class ) ); - assertTrue( resp.getStatus() == 200 ); - - // now change a field - node.setVersion( "1.0.2" ); - reqEntity = Entity.entity( node, MediaType.APPLICATION_JSON ); - - // update currently fails... - resp = target( entry_path ) - .path( node.getFqdn()) - .request() - .put( reqEntity, Response.class ); - System.out.println( "PUT " + entry_path + "/" + node.getFqdn() + " resp=" + resp.getStatus() + " " + resp.readEntity(String.class)); - assertTrue( resp.getStatus() == 404 ); - - } - - +import static javax.ws.rs.client.Entity.entity; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + + +public class DR_NodeResourceTest { + + private static final DmaapObjectFactory DMAAP_OBJECT_FACTORY = new DmaapObjectFactory(); + private static FastJerseyTestContainer testContainer; + + @BeforeClass + public static void setUpClass() throws Exception { + DatabaseClass.getDmaap().init(DMAAP_OBJECT_FACTORY.genDmaap()); + + testContainer = new FastJerseyTestContainer(new ResourceConfig() + .register(DR_NodeResource.class)); + testContainer.init(); + } + + @AfterClass + public static void tearDownClass() throws Exception { + testContainer.destroy(); + /*TODO: Cannot cleanup yet until still other Resources tests depends on the static DB content + + DatabaseClass.clearDatabase(); + DatabaseClass.getDmaap().remove();*/ + } + + @Test + public void getDr_Nodes_test() { + Response response = testContainer.target("dr_nodes").request().get(Response.class); + System.out.println("GET dr_subs response=" + response.getStatus()); + + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + } + + @Test + public void addDr_Node_shouldReturnError_whenNoLocationAndFqdnProvided() { + DR_Node node = new DR_Node(null, null, "hostName", "1.0"); + Entity<DR_Node> requestedEntity = entity(node, APPLICATION_JSON); + + Response response = testContainer.target("dr_nodes") + .request() + .post(requestedEntity, Response.class); + + assertEquals(400, response.getStatus()); + ApiError responseError = response.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("dcaeLocation, fqdn", responseError.getFields()); + } + + @Test + public void addDr_Node_shouldReturnError_whenDrNodeWithGiveFqdnAlreadyExists() { + DR_Node node = new DR_Node("fqdn", "location", "hostName", "1.0"); + + addDrNode(node); + Response response = addDrNode(node); + + assertEquals(409, response.getStatus()); + ApiError responseError = response.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("fqdn", responseError.getFields()); + assertEquals("Node fqdn already exists", responseError.getMessage()); + } + + @Test + public void addDr_Node_shouldExecuteSuccessfully() { + DR_Node node = new DR_Node("fqdn", "location", "hostName", "1.0"); + + Response response = addDrNode(node); + + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + assertDrNodeExistInDB(response.readEntity(DR_Node.class)); + } + + @Test + public void updateDr_Node_shouldReturnError_whenNoLocationAndFqdnProvided() { + DR_Node node = new DR_Node(null, null, "hostName", "1.0"); + Entity<DR_Node> requestedEntity = entity(node, APPLICATION_JSON); + + Response response = testContainer.target("dr_nodes") + .path("fqdn") + .request() + .put(requestedEntity, Response.class); + + assertEquals(400, response.getStatus()); + ApiError responseError = response.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("dcaeLocation, fqdn", responseError.getFields()); + } + + @Test + public void updateDr_Node_shouldReturnError_whenNoExistingFqdnProvided() { + DR_Node node = new DR_Node("fqdn", "location", "hostName", "1.0"); + Entity<DR_Node> requestedEntity = entity(node, APPLICATION_JSON); + + Response response = testContainer.target("dr_nodes") + .path("") + .request() + .put(requestedEntity, Response.class); + + assertEquals(405, response.getStatus()); + } + + @Test + public void updateDr_Node_shouldReturnError_whenDrNodeForUpdateDoesNotExistInDb() { + DR_Node node = new DR_Node("fqdn", "location", "hostName", "1.0"); + Entity<DR_Node> requestedEntity = entity(node, APPLICATION_JSON); + + Response response = testContainer.target("dr_nodes") + .path(node.getFqdn()) + .request() + .put(requestedEntity, Response.class); + + assertEquals(404, response.getStatus()); + ApiError responseError = response.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("fqdn", responseError.getFields()); + assertEquals("Node " + node.getFqdn() + " does not exist", responseError.getMessage()); + } + + @Test + public void updateDr_Node_ShouldExecuteSuccessfully() { + DR_Node toUpdate = new DR_Node("fqdn", "location", "hostName", "1.0"); + Entity<DR_Node> requestedEntity = entity(toUpdate, APPLICATION_JSON); + + addDrNode(new DR_Node("fqdn", "old_location", "old_hostName", "old_1.0")); + Response response = testContainer.target("dr_nodes") + .path(toUpdate.getFqdn()) + .request() + .put(requestedEntity, Response.class); + + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + assertEquals(toUpdate, response.readEntity(DR_Node.class)); + } + + @Test + public void deleteDr_Node_shouldReturnError_whenDrNodeForDeleteDoesNotExistInDb() { + Response response = testContainer.target("dr_nodes") + .path("fqdn") + .request() + .delete(); + + assertEquals(404, response.getStatus()); + ApiError responseError = response.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("fqdn", responseError.getFields()); + assertEquals("Node fqdn does not exist", responseError.getMessage()); + } + + @Test + public void deleteDr_Node_shouldReturnError_whenNoExistingFqdnProvided() { + Response response = testContainer.target("dr_nodes") + .path("") + .request() + .delete(); + + assertEquals(405, response.getStatus()); + } + + @Test + public void deleteDr_Node_shouldExecuteSuccessfully() { + DR_Node node = new DR_Node("fqdn", "location", "hostName", "1.0"); + + addDrNode(node); + Response response = testContainer.target("dr_nodes") + .path("fqdn") + .request() + .delete(); + + assertEquals(204, response.getStatus()); + } + + @Test + public void getDr_Node_shouldReturnError_whenDrNodeForDeleteDoesNotExistInDb() { + Response response = testContainer.target("dr_nodes") + .path("fqdn") + .request() + .get(); + + assertEquals(404, response.getStatus()); + ApiError responseError = response.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("fqdn", responseError.getFields()); + assertEquals("Node fqdn does not exist", responseError.getMessage()); + } + + private Response addDrNode(DR_Node node) { + return testContainer.target("dr_nodes") + .request() + .post(entity(node, APPLICATION_JSON), Response.class); + } + + private void assertDrNodeExistInDB(DR_Node created) { + Response response = testContainer.target("dr_nodes") + .path(created.getFqdn()) + .request() + .get(); + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + assertEquals(created, response.readEntity(DR_Node.class)); + } + + @Before + public void cleanupDatabase() { + DatabaseClass.clearDatabase(); + } } diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/DR_SubResourceTest.java b/src/test/java/org/onap/dmaap/dbcapi/resources/DR_SubResourceTest.java index 9ba5776..f812b3d 100644 --- a/src/test/java/org/onap/dmaap/dbcapi/resources/DR_SubResourceTest.java +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/DR_SubResourceTest.java @@ -1,9 +1,8 @@ - /*- * ============LICENSE_START======================================================= * org.onap.dmaap * ================================================================================ - * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,211 +18,426 @@ * ============LICENSE_END========================================================= */ package org.onap.dmaap.dbcapi.resources; -import org.onap.dmaap.dbcapi.model.*; -import org.onap.dmaap.dbcapi.service.*; -import org.onap.dmaap.dbcapi.testframework.DmaapObjectFactory; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import java.util.*; -import java.sql.*; - -import org.glassfish.jersey.test.JerseyTest; -import org.glassfish.jersey.server.ResourceConfig; import javax.ws.rs.client.Entity; -import javax.ws.rs.core.Application; -import javax.ws.rs.core.Response; import javax.ws.rs.core.MediaType; -import javax.ws.rs.Path; -import javax.ws.rs.GET; - -public class DR_SubResourceTest extends JerseyTest{ - - static DmaapObjectFactory factory = new DmaapObjectFactory(); - - @Override - protected Application configure() { - return new ResourceConfig() - .register( DR_SubResource.class ) - .register( FeedResource.class ) - .register( DcaeLocationResource.class ) - .register( DmaapResource.class ); - } - - String d, un, up, f, p; - - @Before - public void preTest() throws Exception { - try { - - Dmaap dmaap = factory.genDmaap(); - Entity<Dmaap> reqEntity = Entity.entity( dmaap, MediaType.APPLICATION_JSON ); - Response resp = target( "dmaap").request().post( reqEntity, Response.class ); - System.out.println( resp.getStatus() ); - assertTrue( resp.getStatus() == 200 ); - }catch (Exception e ) { - } - try { - DcaeLocation loc = factory.genDcaeLocation( "central" ); - Entity<DcaeLocation> reqEntity = Entity.entity( loc, MediaType.APPLICATION_JSON ); - Response resp = target( "dcaeLocations").request().post( reqEntity, Response.class ); - System.out.println( "POST dcaeLocation resp=" + resp.getStatus() + " " + resp.readEntity( String.class )); - if ( resp.getStatus() != 409 ) { - assertTrue( resp.getStatus() == 201 ); - } - } catch (Exception e ) { - } - - - } -/* - @Before - public void setUp() throws Exception { - d = "central-onap"; - un = "user1"; - up = "secretW0rd"; - f = "234"; - p = "678"; - } - - @After - public void tearDown() throws Exception { - } -*/ - - - -/* may conflict with test framework! - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } -*/ - - private Feed addFeed( String name, String desc ) { - Feed feed = new Feed( name, "1.0", desc, "dgl", "unrestricted" ); - Entity<Feed> reqEntity = Entity.entity( feed, MediaType.APPLICATION_JSON ); - Response resp = target( "feeds").request().post( reqEntity, Response.class ); - int rc = resp.getStatus(); - System.out.println( "POST feed resp=" + rc ); - assertTrue( rc == 200 || rc == 409 ); - feed = resp.readEntity( Feed.class ); - return feed; - } - - private DR_Sub addSub( String d, String un, String up, String feedId ) { - DR_Sub dr_sub = new DR_Sub( d, un, up, feedId, - "https://subscriber.onap.org/foo", "https://dr-prov/sublog", true ); - - Entity<DR_Sub> reqEntity2 = Entity.entity( dr_sub, MediaType.APPLICATION_JSON); - Response resp = target( "dr_subs").request().post( reqEntity2, Response.class); - System.out.println( "POST dr_subs resp=" + resp.getStatus() ); - assertTrue( resp.getStatus() == 201 ); - dr_sub = resp.readEntity( DR_Sub.class ); - - return dr_sub; - } - private DR_Sub addSubByName( String d, String un, String up, String feedName ) { - DR_Sub dr_sub = new DR_Sub( d, un, up, null, - "https://subscriber.onap.org/foo", "https://dr-prov/sublog", true ); - - dr_sub.setFeedName(feedName); - - Entity<DR_Sub> reqEntity2 = Entity.entity( dr_sub, MediaType.APPLICATION_JSON); - Response resp = target( "dr_subs").request().post( reqEntity2, Response.class); - System.out.println( "POST dr_subs resp=" + resp.getStatus() ); - assertTrue( resp.getStatus() == 201 ); - dr_sub = resp.readEntity( DR_Sub.class ); - - return dr_sub; - } - - @Test - public void GetTest() { - Response resp = target( "dr_subs").request().get( Response.class ); - System.out.println( "GET dr_subs resp=" + resp.getStatus() ); - - assertTrue( resp.getStatus() == 200 ); - } - - @Test - public void PostTest() { - - Feed feed = addFeed( "subPostTest", "post unit test" ); - System.out.println( "subPostTest: feedId=" + feed.getFeedId()); - - String d, un, up; - d = "central-onap"; - un = "user1"; - up = "secretW0rd"; - - DR_Sub dr_pub = addSub( d, un, up, feed.getFeedId() ); - } - - @Test - public void PostTestByName() { - - Feed feed = addFeed( "subPostTest2", "post unit test" ); - System.out.println( "subPostTest2: feedId=" + feed.getFeedId()); - - String d, un, up; - d = "central-onap"; - un = "user1"; - up = "secretW0rd"; - - DR_Sub dr_pub = addSubByName( d, un, up, feed.getFeedName() ); - } - - @Test - public void PutTest() { - - Feed feed = addFeed( "subPutTest", "put unit test"); - String d, un, up; - d = "central-onap"; - un = "user1"; - up = "secretW0rd"; - - DR_Sub dr_sub = addSub( d, un, up, feed.getFeedId() ); - - dr_sub.setUserpwd("newSecret"); - Entity<DR_Sub> reqEntity2 = Entity.entity( dr_sub, MediaType.APPLICATION_JSON); - Response resp = target( "dr_subs") - .path( dr_sub.getSubId() ) - .request() - .put( reqEntity2, Response.class); - System.out.println( "PUT dr_subs resp=" + resp.getStatus() ); - assertTrue( resp.getStatus() == 200 ); - } - - -// TODO: figure out how to check delete() response - @Test - public void DelTest() { - - Feed feed = addFeed( "subDelTest", "del unit test"); - String d, un, up; - d = "central-onap"; - un = "user1"; - up = "secretW0rd"; - - DR_Sub dr_sub = addSub( d, un, up, feed.getFeedId() ); - - Entity<DR_Sub> reqEntity2 = Entity.entity( dr_sub, MediaType.APPLICATION_JSON); - Response resp = target( "dr_subs") - .path( dr_sub.getSubId() ) - .request() - .delete(); - System.out.println( "DEL dr_subs resp=" + resp.getStatus() ); - assertTrue( resp.getStatus() == 204 ); - } - +import javax.ws.rs.core.Response; +import org.glassfish.jersey.server.ResourceConfig; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.dmaap.dbcapi.database.DatabaseClass; +import org.onap.dmaap.dbcapi.model.ApiError; +import org.onap.dmaap.dbcapi.model.DR_Sub; +import org.onap.dmaap.dbcapi.model.Feed; +import org.onap.dmaap.dbcapi.testframework.DmaapObjectFactory; +public class DR_SubResourceTest { + + private static final DmaapObjectFactory DMAAP_OBJECT_FACTORY = new DmaapObjectFactory(); + + private static final String DCAE_LOCATION_NAME = "central-onap"; + private static final String USERNAME = "user1"; + private static final String USRPWD = "secretW0rd"; + private static final String DELIVERY_URL = "https://subscriber.onap.org/delivery/id"; + private static final String LOG_URL = "https://dr-prov/sublog/id"; + private static final String DELIVERY_URL_TEMPLATE = "https://subscriber.onap.org/delivery/"; + private static final String LOG_URL_TEMPLATE = "https://dr-prov/sublog/"; + private static FastJerseyTestContainer testContainer; + + @BeforeClass + public static void setUpClass() throws Exception { + //TODO: init is still needed here to assure that dmaap is not null + DatabaseClass.getDmaap().init(DMAAP_OBJECT_FACTORY.genDmaap()); + + testContainer = new FastJerseyTestContainer(new ResourceConfig() + .register(DR_SubResource.class) + .register(FeedResource.class)); + testContainer.init(); + } + + @AfterClass + public static void tearDownClass() throws Exception { + testContainer.destroy(); + /*TODO: Cannot cleanup yet until still other Resources tests depends on the static DB content + + DatabaseClass.clearDatabase(); + DatabaseClass.getDmaap().remove();*/ + } + + @Before + public void cleanupDatabase() { + DatabaseClass.clearDatabase(); + } + + //TODO: figure out generic entity list unmarshall to check the entity list + @Test + public void getDr_Subs_test() { + Response resp = testContainer.target("dr_subs").request().get(Response.class); + System.out.println("GET dr_subs resp=" + resp.getStatus()); + + assertEquals(200, resp.getStatus()); + assertTrue(resp.hasEntity()); + } + + @Test + public void addDr_Sub_shallReturnError_whenNoFeedIdAndFeedNameInSubProvided() { + //given + DR_Sub drSub = new DR_Sub(DCAE_LOCATION_NAME, USERNAME, USRPWD, null, DELIVERY_URL, LOG_URL, true); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .request() + .post(requestedEntity, Response.class); + + //then + assertEquals(400, resp.getStatus()); + ApiError responseError = resp.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("feedName", responseError.getFields()); + } + + @Test + public void addDr_Sub_shallReturnError_whenFeedNameProvided_butFeedNotExist() { + //given + String notExistingFeedName = "notRealFead"; + DR_Sub drSub = new DR_Sub(DCAE_LOCATION_NAME, USERNAME, USRPWD, null, DELIVERY_URL, LOG_URL, true); + drSub.setFeedName(notExistingFeedName); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .request() + .post(requestedEntity, Response.class); + + //then + assertEquals(404, resp.getStatus()); + ApiError responseError = resp.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("feedName", responseError.getFields()); + } + + @Test + public void addDr_Sub_shallReturnError_whenFeedNameProvided_andManyFeedsWithTheSameNameInDB() { + //given + String notDistinctFeedName = "notDistinctFeedName"; + Feed feed1 = new Feed(notDistinctFeedName, "1.0", "description", "dgl", "unrestricted"); + Feed feed2 = new Feed(notDistinctFeedName, "2.0", "description", "dgl", "unrestricted"); + DatabaseClass.getFeeds().put("1", feed1); + DatabaseClass.getFeeds().put("2", feed2); + DR_Sub drSub = new DR_Sub(DCAE_LOCATION_NAME, USERNAME, USRPWD, null, DELIVERY_URL, LOG_URL, true); + drSub.setFeedName(notDistinctFeedName); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .request() + .post(requestedEntity, Response.class); + + //then + assertEquals(409, resp.getStatus()); + ApiError responseError = resp.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("feedName", responseError.getFields()); + } + + @Test + public void addDr_Sub_shallReturnError_whenFeedIdProvided_butFeedNotExist() { + //given + DR_Sub drSub = new DR_Sub(DCAE_LOCATION_NAME, USERNAME, USRPWD, "someFakeFeedId", DELIVERY_URL, LOG_URL, true); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .request() + .post(requestedEntity, Response.class); + + //then + assertEquals(404, resp.getStatus()); + ApiError responseError = resp.readEntity(ApiError.class); + assertNotNull(responseError); + assertTrue(responseError.getFields().contains("feedId")); + } + + @Test + public void addDr_Sub_shallExecuteSuccessfully_whenValidFeedIdProvided() { + //given + String feedId = assureFeedIsInDB(); + DR_Sub drSub = new DR_Sub(DCAE_LOCATION_NAME, USERNAME, USRPWD, feedId, DELIVERY_URL, LOG_URL, true); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .request() + .post(requestedEntity, Response.class); + + //then + assertEquals(201, resp.getStatus()); + assertTrue(resp.hasEntity()); + DR_Sub created = resp.readEntity(DR_Sub.class); + assertSubscriptionExistInDB(created); + } + + @Test + public void addDr_Sub_shallExecuteSuccessfully_whenValidFeedNameProvided() { + //given + String feedName = "testFeed"; + addFeed(feedName, "test feed"); + DR_Sub drSub = new DR_Sub(DCAE_LOCATION_NAME, USERNAME, USRPWD, null, DELIVERY_URL, LOG_URL, true); + drSub.setFeedName(feedName); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .request() + .post(requestedEntity, Response.class); + + //then + assertEquals(201, resp.getStatus()); + assertTrue(resp.hasEntity()); + DR_Sub created = resp.readEntity(DR_Sub.class); + assertSubscriptionExistInDB(created); + } + + + @Test + public void updateDr_Sub_shallReturnError_whenNoFeedIdInSubProvided() { + //given + String subId = "1234"; + DR_Sub drSub = new DR_Sub(DCAE_LOCATION_NAME, USERNAME, USRPWD, null, DELIVERY_URL, LOG_URL, true); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .path(subId) + .request() + .put(requestedEntity, Response.class); + + //then + assertEquals(400, resp.getStatus()); + ApiError responseError = resp.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("feedId", responseError.getFields()); + } + + @Test + public void updateDr_Sub_shallReturnError_whenNoDCAELocationInSubProvided() { + //given + String subId = "1234"; + DR_Sub drSub = new DR_Sub(null, USERNAME, USRPWD, "someFeedId", DELIVERY_URL, LOG_URL, true); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .path(subId) + .request() + .put(requestedEntity, Response.class); + + //then + assertEquals(400, resp.getStatus()); + ApiError responseError = resp.readEntity(ApiError.class); + assertNotNull(responseError); + assertEquals("dcaeLocationName", responseError.getFields()); + } + + @Test + public void updateDr_Sub_shallReturnError_whenFeedWithGivenIdInSubNotExists() { + //given + String subId = "1234"; + DR_Sub drSub = new DR_Sub(DCAE_LOCATION_NAME, USERNAME, USRPWD, "someFeedId", DELIVERY_URL, LOG_URL, true); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .path(subId) + .request() + .put(requestedEntity, Response.class); + + //then + assertEquals(404, resp.getStatus()); + assertNotNull(resp.readEntity(ApiError.class)); + } + + @Test + public void updateDr_Sub_shallReturnSuccess_whenAddingNewSubscription() { + //given + String subId = "31"; + String feedId = assureFeedIsInDB(); + DR_Sub drSub = new DR_Sub(DCAE_LOCATION_NAME, USERNAME, USRPWD, feedId, null, null, true); + Entity<DR_Sub> requestedEntity = Entity.entity(drSub, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .path(subId) + .request() + .put(requestedEntity, Response.class); + + //then + assertEquals(200, resp.getStatus()); + + DR_Sub createdDrSub = resp.readEntity(DR_Sub.class); + assertNotNull(createdDrSub.getLastMod()); + assertEquals(subId, createdDrSub.getSubId()); + assertEquals(DCAE_LOCATION_NAME, createdDrSub.getDcaeLocationName()); + assertEquals(USERNAME, createdDrSub.getUsername()); + assertEquals(USRPWD, createdDrSub.getUserpwd()); + assertEquals(DELIVERY_URL_TEMPLATE + subId, createdDrSub.getDeliveryURL()); + assertEquals(LOG_URL_TEMPLATE + subId, createdDrSub.getLogURL()); + + assertSubscriptionExistInDB(createdDrSub); + } + + @Test + public void updateDr_Sub_shallReturnSuccess_whenUpdatingExistingSubscription() { + //given + String feedId = assureFeedIsInDB(); + DR_Sub existingDrSub = addSub(DCAE_LOCATION_NAME, USERNAME, USRPWD, feedId); + DR_Sub drSubUpdate = new DR_Sub("newDcaeLocationName", "newUserName", "newUserPwd", feedId, null, null, false); + Entity<DR_Sub> requestedEntity = Entity.entity(drSubUpdate, MediaType.APPLICATION_JSON); + + //when + Response resp = testContainer.target("dr_subs") + .path(existingDrSub.getSubId()) + .request() + .put(requestedEntity, Response.class); + + //then + assertEquals(200, resp.getStatus()); + + DR_Sub updatedDrSub = resp.readEntity(DR_Sub.class); + assertNotNull(updatedDrSub.getLastMod()); + assertEquals(existingDrSub.getSubId(), updatedDrSub.getSubId()); + assertEquals(drSubUpdate.getDcaeLocationName(), updatedDrSub.getDcaeLocationName()); + assertEquals(drSubUpdate.getUsername(), updatedDrSub.getUsername()); + assertEquals(drSubUpdate.getUserpwd(), updatedDrSub.getUserpwd()); + assertEquals(DELIVERY_URL_TEMPLATE + existingDrSub.getSubId(), updatedDrSub.getDeliveryURL()); + assertEquals(LOG_URL_TEMPLATE + existingDrSub.getSubId(), updatedDrSub.getLogURL()); + + assertSubscriptionExistInDB(updatedDrSub); + } + + @Test + public void deleteDr_Sub_shouldDeleteSubscriptionWithSuccess() { + //given + String feedId = assureFeedIsInDB(); + DR_Sub dr_sub = addSub(DCAE_LOCATION_NAME, USERNAME, USRPWD, feedId); + + //when + Response resp = testContainer.target("dr_subs") + .path(dr_sub.getSubId()) + .request() + .delete(); + + //then + assertEquals("Shall delete subscription with success", 204, resp.getStatus()); + assertFalse("No entity object shall be returned",resp.hasEntity()); + assertSubscriptionNotExistInDB(dr_sub.getSubId()); + } + + @Test + public void deleteDr_Sub_shouldReturnErrorResponse_whenGivenSubIdNotFound() { + //given + String notExistingSubId = "6789"; + + //when + Response resp = testContainer.target("dr_subs") + .path(notExistingSubId) + .request() + .delete(); + + //then + assertEquals("Shall return error, when trying to delete not existing subscription", 404, resp.getStatus()); + assertNotNull(resp.readEntity(ApiError.class)); + } + + @Test + public void get_shallReturnExistingObject() { + //given + String feedId = assureFeedIsInDB(); + DR_Sub dr_sub = addSub(DCAE_LOCATION_NAME, USERNAME, USRPWD, feedId); + + //when + Response resp = testContainer.target("dr_subs") + .path(dr_sub.getSubId()) + .request() + .get(); + + //ten + assertEquals("Subscription shall be found",200, resp.getStatus()); + assertEquals("Retrieved object shall be equal to eh one put into DB", dr_sub, resp.readEntity(DR_Sub.class)); + } + + @Test + public void get_shouldReturnError_whenSubWithIdNotFound() { + //given + String notExistingSubId = "1234"; + + //when + Response resp = testContainer.target("dr_subs") + .path(notExistingSubId) + .request() + .get(); + + //then + assertEquals("Subscription shall not be found", 404, resp.getStatus()); + assertNotNull(resp.readEntity(ApiError.class)); + } + + private Feed addFeed(String name, String desc) { + Feed feed = new Feed(name, "1.0", desc, "dgl", "unrestricted"); + Entity<Feed> reqEntity = Entity.entity(feed, MediaType.APPLICATION_JSON); + Response resp = testContainer.target("feeds").request().post(reqEntity, Response.class); + int rc = resp.getStatus(); + System.out.println("POST feed resp=" + rc); + assertTrue(rc == 200 || rc == 409); + feed = resp.readEntity(Feed.class); + return feed; + } + + private DR_Sub addSub(String d, String un, String up, String feedId) { + DR_Sub dr_sub = new DR_Sub(d, un, up, feedId, + "https://subscriber.onap.org/foo", "https://dr-prov/sublog", true); + + Entity<DR_Sub> reqEntity2 = Entity.entity(dr_sub, MediaType.APPLICATION_JSON); + Response resp = testContainer.target("dr_subs").request().post(reqEntity2, Response.class); + System.out.println("POST dr_subs resp=" + resp.getStatus()); + assertEquals(201, resp.getStatus()); + dr_sub = resp.readEntity(DR_Sub.class); + + return dr_sub; + } + + private String assureFeedIsInDB() { + Feed feed = addFeed("SubscriberTestFeed", "feed for DR_Sub testing"); + assertNotNull("Feed shall be added into DB properly", feed); + return feed.getFeedId(); + } + + + private void assertSubscriptionNotExistInDB(String subId) { + assertEquals(404, testContainer.target("dr_subs") + .path(subId) + .request() + .get() + .getStatus()); + } + + private void assertSubscriptionExistInDB(DR_Sub sub) { + Response response = testContainer.target("dr_subs") + .path(sub.getSubId()) + .request() + .get(); + assertEquals(200, response.getStatus()); + assertTrue(response.hasEntity()); + assertEquals(sub, response.readEntity(DR_Sub.class)); + } } diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/FastJerseyTestContainer.java b/src/test/java/org/onap/dmaap/dbcapi/resources/FastJerseyTestContainer.java new file mode 100644 index 0000000..8d38a9f --- /dev/null +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/FastJerseyTestContainer.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dmaap + * ================================================================================ + * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dmaap.dbcapi.resources; + +import org.glassfish.jersey.test.JerseyTest; + +import javax.ws.rs.core.Application; + +class FastJerseyTestContainer extends JerseyTest { + + FastJerseyTestContainer(Application jaxrsApplication) { + super(jaxrsApplication); + } + + void init() throws Exception { + this.setUp(); + } + + void destroy() throws Exception { + this.tearDown(); + } +}
\ No newline at end of file diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResourceTest.java b/src/test/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResourceTest.java index 05bdeea..7367471 100644 --- a/src/test/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResourceTest.java +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResourceTest.java @@ -28,7 +28,9 @@ import javax.ws.rs.core.Response; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; +import org.junit.Before; import org.junit.Test; +import org.onap.dmaap.dbcapi.database.DatabaseClass; import org.onap.dmaap.dbcapi.model.DcaeLocation; import org.onap.dmaap.dbcapi.model.MR_Cluster; import org.onap.dmaap.dbcapi.testframework.DmaapObjectFactory; @@ -50,11 +52,12 @@ public class MR_ClusterResourceTest extends JerseyTest { -/* may conflict with test framework! + @Before - public void preTest() throws Exception { + public void init() throws Exception { + DatabaseClass.clearDatabase(); } - +/* @After public void tearDown() throws Exception { } diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/RequestTimeLogFilterTest.java b/src/test/java/org/onap/dmaap/dbcapi/resources/RequestTimeLogFilterTest.java new file mode 100644 index 0000000..0c88c0c --- /dev/null +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/RequestTimeLogFilterTest.java @@ -0,0 +1,78 @@ +/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dmaap.dbcapi.resources;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import com.att.eelf.configuration.EELFLogger;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerResponseContext;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RequestTimeLogFilterTest {
+
+ private Clock clock ;
+ private RequestTimeLogFilter requestTimeLogFilter;
+ public static final long START = 1L;
+ @Mock
+ private ContainerRequestContext requestContext;
+ @Mock
+ private ContainerResponseContext responseContext;
+ @Mock
+ private EELFLogger logger;
+
+
+ @Before
+ public void setup() {
+ clock = Clock.fixed(Instant.parse("1970-01-01T00:00:10Z"), ZoneId.systemDefault());
+ requestTimeLogFilter = new RequestTimeLogFilter(logger, clock);
+ }
+
+ @Test
+ public void shouldHaveDefaultConstructor() {
+ assertNotNull(new RequestTimeLogFilter());
+ }
+
+ @Test
+ public void filterShouldSetStartTimestampProperty() {
+ requestTimeLogFilter.filter(requestContext);
+ verify(requestContext).setProperty("start",clock.millis());
+ }
+
+ @Test
+ public void filterShouldPrintElapsedTime() {
+ when(requestContext.getProperty("start")).thenReturn(START);
+
+ requestTimeLogFilter.filter(requestContext, responseContext);
+
+ verify(logger).info(anyString(),eq(clock.millis() - START));
+ }
+}
\ No newline at end of file diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/RequiredCheckerTest.java b/src/test/java/org/onap/dmaap/dbcapi/resources/RequiredCheckerTest.java new file mode 100644 index 0000000..f07058b --- /dev/null +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/RequiredCheckerTest.java @@ -0,0 +1,86 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 NOKIA Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dmaap.dbcapi.resources; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onap.dmaap.dbcapi.model.ApiError; + +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; +import static org.junit.Assert.fail; + +public class RequiredCheckerTest { + + private static final String NAME = "field_name"; + @Rule + public ExpectedException thrown = ExpectedException.none(); + private RequiredChecker requiredChecker = new RequiredChecker(); + + + @Test + public void required_shouldThrowExceptionWhenObjectIsNull() throws RequiredFieldException { + thrown.expect(RequiredFieldException.class); + thrown.expect(new ApiErrorMatcher(new ApiError(BAD_REQUEST.getStatusCode(), + "missing required field", NAME))); + + requiredChecker.required(NAME, null); + } + + @Test + public void required_shouldThrowExceptionWhenRegexValidationFailed() throws RequiredFieldException { + thrown.expect(RequiredFieldException.class); + thrown.expect(new ApiErrorMatcher(new ApiError(BAD_REQUEST.getStatusCode(), + "value 'with white space' violates regexp check '^\\S+$'", NAME))); + + requiredChecker.required(NAME, "with white space", "^\\S+$"); + } + + @Test + public void required_shouldPassValidation() { + try { + requiredChecker.required(NAME, "value", "^\\S+$"); + } catch (RequiredFieldException e) { + fail("No exception should be thrown"); + } + } + + class ApiErrorMatcher extends BaseMatcher { + + private final ApiError expectedApiEror; + + ApiErrorMatcher(ApiError expectedApiEror) { + this.expectedApiEror = expectedApiEror; + } + + @Override + public boolean matches(Object exception) { + return expectedApiEror.equals(((RequiredFieldException) exception).getApiError()); + } + + @Override + public void describeTo(Description description) { + description.appendText("Following ApiError is expected: ").appendValue(expectedApiEror); + } + } +}
\ No newline at end of file diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/RequiredFieldExceptionTest.java b/src/test/java/org/onap/dmaap/dbcapi/resources/RequiredFieldExceptionTest.java new file mode 100644 index 0000000..d3dcc42 --- /dev/null +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/RequiredFieldExceptionTest.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dmaap + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright (c) 2019 IBM + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dmaap.dbcapi.resources; + +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.onap.dmaap.dbcapi.model.ApiError; + +public class RequiredFieldExceptionTest { + ApiError apiError; + RequiredFieldException requiredFieldException; + String expectedValue; + + @Before + public void setUp() { + apiError = new ApiError(BAD_REQUEST.getStatusCode(), "value 'with white space' violates regexp check '^\\S+$'", + "field_name"); + + expectedValue = "RequiredFieldException{" + "apiError=" + apiError + '}'; + + requiredFieldException = new RequiredFieldException(apiError); + } + + @Test + public void testRequiredFieldExceptionToString() { + assertEquals(expectedValue, requiredFieldException.toString()); + } +} diff --git a/src/test/java/org/onap/dmaap/dbcapi/resources/TopicResourceTest.java b/src/test/java/org/onap/dmaap/dbcapi/resources/TopicResourceTest.java index ac22e17..88840fe 100644 --- a/src/test/java/org/onap/dmaap/dbcapi/resources/TopicResourceTest.java +++ b/src/test/java/org/onap/dmaap/dbcapi/resources/TopicResourceTest.java @@ -30,6 +30,7 @@ import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.Before; import org.junit.Test; +import org.onap.dmaap.dbcapi.database.DatabaseClass; import org.onap.dmaap.dbcapi.model.DcaeLocation; import org.onap.dmaap.dbcapi.model.Dmaap; import org.onap.dmaap.dbcapi.model.MR_Cluster; @@ -54,15 +55,14 @@ public class TopicResourceTest extends JerseyTest { private static final String fmt = "%24s: %s%n"; - - @Before public void preTest() throws Exception { + DatabaseClass.clearDatabase(); try { Dmaap dmaap = factory.genDmaap(); Entity<Dmaap> reqEntity = Entity.entity( dmaap, MediaType.APPLICATION_JSON ); - Response resp = target( "dmaap").request().post( reqEntity, Response.class ); + Response resp = target( "dmaap").request().put( reqEntity, Response.class ); System.out.println( resp.getStatus() ); assertTrue( resp.getStatus() == 200 ); }catch (Exception e ) { diff --git a/src/test/java/org/onap/dmaap/dbcapi/service/ApiServiceTest.java b/src/test/java/org/onap/dmaap/dbcapi/service/ApiServiceTest.java index 33cce9d..dccfadf 100644 --- a/src/test/java/org/onap/dmaap/dbcapi/service/ApiServiceTest.java +++ b/src/test/java/org/onap/dmaap/dbcapi/service/ApiServiceTest.java @@ -59,22 +59,4 @@ public class ApiServiceTest { rh.reflect( "org.onap.dmaap.dbcapi.service.ApiService", "set", v ); } - - @Test - public void test3() { - ApiService nd = new ApiService(); - nd.setAuth( "auth" ); - try { - nd.required( "aName", null, "anExpr" ); - } catch ( RequiredFieldException rfe ) { - } - try { - nd.checkAuthorization( "authval", "/uri/Path", "GET" ); - nd.checkAuthorization(); - } catch ( AuthenticationErrorException aee ) { - } catch ( Exception e ) { - } - } - - } diff --git a/src/test/java/org/onap/dmaap/dbcapi/service/DmaapServiceTest.java b/src/test/java/org/onap/dmaap/dbcapi/service/DmaapServiceTest.java index 7029bd2..c1fa0fd 100644 --- a/src/test/java/org/onap/dmaap/dbcapi/service/DmaapServiceTest.java +++ b/src/test/java/org/onap/dmaap/dbcapi/service/DmaapServiceTest.java @@ -19,16 +19,11 @@ */ package org.onap.dmaap.dbcapi.service; -import org.onap.dmaap.dbcapi.model.*; -import org.onap.dmaap.dbcapi.testframework.ReflectionHarness; -import org.onap.dmaap.dbcapi.aaf.*; - -import static org.junit.Assert.*; - import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.util.List; +import org.onap.dmaap.dbcapi.model.Dmaap; +import org.onap.dmaap.dbcapi.testframework.ReflectionHarness; public class DmaapServiceTest { diff --git a/src/test/java/org/onap/dmaap/dbcapi/service/FeedServiceTest.java b/src/test/java/org/onap/dmaap/dbcapi/service/FeedServiceTest.java index d601bc4..acbc738 100644 --- a/src/test/java/org/onap/dmaap/dbcapi/service/FeedServiceTest.java +++ b/src/test/java/org/onap/dmaap/dbcapi/service/FeedServiceTest.java @@ -95,5 +95,14 @@ public class FeedServiceTest { } + + @Test + public void syncTestHard() { + ApiError err = new ApiError(); + ds.sync( true, err ); + + assert( 200 == err.getCode()); + } + } diff --git a/src/test/java/org/onap/dmaap/dbcapi/util/PermissionBuilderTest.java b/src/test/java/org/onap/dmaap/dbcapi/util/PermissionBuilderTest.java new file mode 100644 index 0000000..1858e47 --- /dev/null +++ b/src/test/java/org/onap/dmaap/dbcapi/util/PermissionBuilderTest.java @@ -0,0 +1,151 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dmaap + * ================================================================================ + * Copyright (C) 2019 Nokia Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dmaap.dbcapi.util; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import javax.servlet.http.HttpServletRequest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.dmaap.dbcapi.model.Dmaap; +import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status; +import org.onap.dmaap.dbcapi.service.DmaapService; + +@RunWith(MockitoJUnitRunner.class) +public class PermissionBuilderTest { + + private static final String DMAAP_NAME = "mr"; + private PermissionBuilder permissionBuilder; + @Mock + private DmaapConfig dmaapConfig; + @Mock + private DmaapService dmaapService; + @Mock + private HttpServletRequest request; + + + @Test + public void updateDmaapInstance_shouldSetBootInstance_whenDmaapIsNotInitialized() { + //given + doReturn(null).when(dmaapService).getDmaap(); + permissionBuilder = new PermissionBuilder(dmaapConfig, dmaapService); + + //when + permissionBuilder.updateDmaapInstance(); + + //then + assertEquals(PermissionBuilder.BOOT_INSTANCE, permissionBuilder.getInstance()); + } + + @Test + public void updateDmaapInstance_shouldSetBootInstance_whenDmaapIsInitializedWithDefaultInstance() { + //given + doReturn(provideDefaultInstance()).when(dmaapService).getDmaap(); + permissionBuilder = new PermissionBuilder(dmaapConfig, dmaapService); + + //when + permissionBuilder.updateDmaapInstance(); + + //then + assertEquals(PermissionBuilder.BOOT_INSTANCE, permissionBuilder.getInstance()); + } + + @Test + public void updateDmaapInstance_shouldSetRealInstance_whenDmaapServiceProvidesOne() { + //given + when(dmaapService.getDmaap()).thenReturn(provideDefaultInstance(), provideRealInstance(DMAAP_NAME)); + permissionBuilder = new PermissionBuilder(dmaapConfig, dmaapService); + + //when + permissionBuilder.updateDmaapInstance(); + + //then + assertEquals(DMAAP_NAME, permissionBuilder.getInstance()); + } + + @Test + public void updateDmaapInstance_shouldNotUpdateDmaapInstance_whenAlreadyInitializedWithRealInstance() { + //given + when(dmaapService.getDmaap()).thenReturn(provideRealInstance(DMAAP_NAME), provideRealInstance("newName")); + permissionBuilder = new PermissionBuilder(dmaapConfig, dmaapService); + + //when + permissionBuilder.updateDmaapInstance(); + + //then + assertEquals(DMAAP_NAME, permissionBuilder.getInstance()); + verify(dmaapService, atMost(1)).getDmaap(); + } + + @Test + public void buildPermission_shouldBuildPermissionWithBootInstance() { + //given + String path = "/dmaap"; + String method = "GET"; + initPermissionBuilder(path, method, provideDefaultInstance()); + + //when + String permission = permissionBuilder.buildPermission(request); + + //then + assertEquals("org.onap.dmaap-bc.api.dmaap|boot|GET", permission); + } + + @Test + public void buildPermission_shouldBuildPermissionWithRealInstance() { + //given + String path = "/subpath/topics/"; + String method = "GET"; + initPermissionBuilder(path, method, provideRealInstance(DMAAP_NAME)); + + //when + String permission = permissionBuilder.buildPermission(request); + + //then + assertEquals("org.onap.dmaap-bc.api.topics|mr|GET", permission); + } + + private void initPermissionBuilder(String path, String method, Dmaap dmaapInstance) { + when(dmaapConfig.getProperty(PermissionBuilder.API_NS_PROP, PermissionBuilder.DEFAULT_API_NS)) + .thenReturn(PermissionBuilder.DEFAULT_API_NS); + when(dmaapService.getDmaap()).thenReturn(dmaapInstance); + permissionBuilder = new PermissionBuilder(dmaapConfig, dmaapService); + + when(request.getPathInfo()).thenReturn(path); + when(request.getMethod()).thenReturn(method); + } + + private Dmaap provideDefaultInstance() { + return new Dmaap("0", "", "", "", "", "", "", ""); + } + + private Dmaap provideRealInstance(String dmaapName) { + Dmaap dmaap = new Dmaap("1", "org.onap.dmaap", dmaapName, "https://dmaap-dr-prov:8443", "", "DCAE_MM_AGENT", "", ""); + dmaap.setStatus(DmaapObject_Status.VALID); + return dmaap; + } + +}
\ No newline at end of file diff --git a/version.properties b/version.properties index 102b722..1eff060 100644 --- a/version.properties +++ b/version.properties @@ -27,7 +27,7 @@ major=1 minor=0 -patch=24 +patch=25 base_version=${major}.${minor}.${patch} # Release must be completed with git revision # in Jenkins |