summaryrefslogtreecommitdiffstats
path: root/cadi/core
diff options
context:
space:
mode:
Diffstat (limited to 'cadi/core')
-rw-r--r--cadi/core/pom.xml2
-rw-r--r--cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java1
-rw-r--r--cadi/core/src/main/java/org/onap/aaf/cadi/filter/MapBathConverter.java170
-rw-r--r--cadi/core/src/main/java/org/onap/aaf/cadi/taf/basic/BasicHttpTaf.java18
-rw-r--r--cadi/core/src/main/java/org/onap/aaf/cadi/util/CSV.java190
-rw-r--r--cadi/core/src/test/java/org/onap/aaf/cadi/config/test/JU_MapBathConverter.java217
-rw-r--r--cadi/core/src/test/java/org/onap/aaf/cadi/util/test/JU_CSV.java122
7 files changed, 719 insertions, 1 deletions
diff --git a/cadi/core/pom.xml b/cadi/core/pom.xml
index 9afde0c8..32b63155 100644
--- a/cadi/core/pom.xml
+++ b/cadi/core/pom.xml
@@ -16,7 +16,7 @@
<groupId>org.onap.aaf.authz</groupId>
<artifactId>cadiparent</artifactId>
<relativePath>..</relativePath>
- <version>2.1.3-SNAPSHOT</version>
+ <version>2.1.4-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java b/cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java
index 088227ed..2479a058 100644
--- a/cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java
+++ b/cadi/core/src/main/java/org/onap/aaf/cadi/config/Config.java
@@ -103,6 +103,7 @@ public class Config {
public static final String CADI_PROTOCOLS = "cadi_protocols";
public static final String CADI_NOAUTHN = "cadi_noauthn";
public static final String CADI_LOC_LIST = "cadi_loc_list";
+ public static final String CADI_BATH_CONVERT = "cadi_bath_convert";
public static final String CADI_USER_CHAIN_TAG = "cadi_user_chain";
public static final String CADI_USER_CHAIN = "USER_CHAIN";
diff --git a/cadi/core/src/main/java/org/onap/aaf/cadi/filter/MapBathConverter.java b/cadi/core/src/main/java/org/onap/aaf/cadi/filter/MapBathConverter.java
new file mode 100644
index 00000000..7a138e97
--- /dev/null
+++ b/cadi/core/src/main/java/org/onap/aaf/cadi/filter/MapBathConverter.java
@@ -0,0 +1,170 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T 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.aaf.cadi.filter;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.xml.ws.Holder;
+
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.Access.Level;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.Symm;
+import org.onap.aaf.cadi.util.CSV;
+import org.onap.aaf.cadi.util.CSV.Visitor;
+
+/**
+ * This Filter is designed to help MIGRATE users from systems that don't match the FQI style.
+ *
+ * Style 1, where just the ID is translated, i.e. OLD => new@something.onap.org, that is acceptable
+ * longer term, because it does not store Creds locally. The passwords are in appropriate systems, but
+ * it's still painful operationally, though it does ease migration.
+ *
+ * Style 3, however, which is Direct match of Authorization Header to replacement, is only there
+ * because some passwords are simply not acceptable for AAF, (too easy, for instance), and it is
+ * not feasible to break Organization Password rules for a Migration. Therefore, this method
+ * should not considered something that is in any way a permanent
+ *
+
+ *
+ * It goes without saying that any file with the password conversion should be protected by "400", etc.
+ *
+ * @author Instrumental (Jonathan)
+ *
+ */
+public class MapBathConverter {
+ private static final String BASIC = "Basic ";
+ private final Map<String,String> map;
+
+ /**
+ * Create with colon separated name value pairs
+ * Enter the entire "Basic dXNlcjpwYXNz" "Authorization" header, where "dXNlcjpwYXNz" is
+ * base64 encoded, which can be created with "cadi" tool (in jar)
+ *
+ * The replacement should also be an exact replacement of what you want. Recognize that
+ * this should be TEMPORARY as you are storing credentials outside the users control.
+ *
+ * @param value
+ * @throws IOException
+ * @throws CadiException
+ */
+ public MapBathConverter(final Access access, final CSV csv) throws IOException, CadiException {
+ map = new TreeMap<>();
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ final Date now = new Date();
+ csv.visit(new Visitor() {
+ @Override
+ public void visit(List<String> row) throws CadiException {
+ if(row.size()<3) {
+ throw new CadiException("CSV file " + csv + " must have at least 2 Basic Auth columns and an Expiration Date(YYYYMMDD) in each row");
+ }
+ try {
+ Date date = sdf.parse(row.get(2));
+ String oldID = row.get(0);
+ String newID = row.get(1);
+ if(date.after(now)) {
+ if(!oldID.startsWith(BASIC) && newID.startsWith(BASIC)) {
+ throw new CadiException("CSV file " + csv + ": Uncredentialed ID " + idFromBasic(oldID,null) +
+ " may not transfer to credentialed ID " + idFromBasic(newID,null));
+ } else {
+ map.put(oldID,newID);
+ access.printf(Level.INIT, "ID Conversion from %s to %s enabled",
+ idFromBasic(oldID,null),
+ idFromBasic(newID,null));
+ }
+ } else {
+ access.printf(Level.INIT, "ID Conversion from %s to %s has expired.",
+ idFromBasic(oldID,null),
+ idFromBasic(newID,null));
+ }
+ } catch (ParseException e) {
+ throw new CadiException("Cannot Parse Date: " + row.get(2));
+ } catch (IOException e) {
+ throw new CadiException(e);
+ }
+ }
+ });
+ }
+
+ private static String idFromBasic(String bath, Holder<String> hpass) throws IOException, CadiException {
+ if(bath.startsWith(BASIC)) {
+ String cred = Symm.base64noSplit.decode(bath.substring(6));
+ int colon = cred.indexOf(':');
+ if(colon<0) {
+ throw new CadiException("Invalid Authentication Credential for " + cred);
+ }
+ if(hpass!=null) {
+ hpass.value = cred.substring(colon+1);
+ }
+ return cred.substring(0, colon);
+ } else {
+ return bath;
+ }
+ }
+
+ /**
+ * use to instantiate entries
+ *
+ * @return
+ */
+ public Map<String,String> map() {
+ return map;
+ }
+
+ public String convert(Access access, final String bath) {
+ String rv = map.get(bath);
+ String cred=null;
+ Holder<String> hpass=null;
+ try {
+ if(rv==null || !rv.startsWith(BASIC)) {
+ if(bath.startsWith(BASIC)) {
+ cred = idFromBasic(bath,(hpass=new Holder<String>()));
+ }
+ }
+
+ if(cred!=null) {
+ if(rv==null) {
+ rv = map.get(cred);
+ }
+ // for SAFETY REASONS, we WILL NOT allow a non validated cred to
+ // pass a password from file. Should be caught from Instation, but...
+ if(rv!=null) {
+ if(rv.startsWith(BASIC)) {
+ return bath;
+ } else {
+ rv = BASIC + Symm.base64noSplit.encode(rv+':'+hpass.value);
+ }
+ }
+ }
+ } catch (IOException | CadiException e) {
+ access.log(e,"Invalid Authorization");
+ }
+
+ return rv;
+ }
+}
diff --git a/cadi/core/src/main/java/org/onap/aaf/cadi/taf/basic/BasicHttpTaf.java b/cadi/core/src/main/java/org/onap/aaf/cadi/taf/basic/BasicHttpTaf.java
index d5f6b032..3466a8d8 100644
--- a/cadi/core/src/main/java/org/onap/aaf/cadi/taf/basic/BasicHttpTaf.java
+++ b/cadi/core/src/main/java/org/onap/aaf/cadi/taf/basic/BasicHttpTaf.java
@@ -34,16 +34,20 @@ import org.onap.aaf.cadi.Access.Level;
import org.onap.aaf.cadi.BasicCred;
import org.onap.aaf.cadi.CachedPrincipal;
import org.onap.aaf.cadi.CachedPrincipal.Resp;
+import org.onap.aaf.cadi.CadiException;
import org.onap.aaf.cadi.CredVal;
import org.onap.aaf.cadi.CredVal.Type;
import org.onap.aaf.cadi.CredValDomain;
import org.onap.aaf.cadi.Taf;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.filter.MapBathConverter;
import org.onap.aaf.cadi.principal.BasicPrincipal;
import org.onap.aaf.cadi.principal.CachedBasicPrincipal;
import org.onap.aaf.cadi.taf.HttpTaf;
import org.onap.aaf.cadi.taf.TafResp;
import org.onap.aaf.cadi.taf.TafResp.RESP;
import org.onap.aaf.cadi.taf.dos.DenialOfServiceTaf;
+import org.onap.aaf.cadi.util.CSV;
/**
* BasicHttpTaf
@@ -66,6 +70,7 @@ public class BasicHttpTaf implements HttpTaf {
private Map<String,CredVal> rbacs = new TreeMap<>();
private boolean warn;
private long timeToLive;
+ private MapBathConverter mapIds;
public BasicHttpTaf(Access access, CredVal rbac, String realm, long timeToLive, boolean turnOnWarning) {
this.access = access;
@@ -73,6 +78,16 @@ public class BasicHttpTaf implements HttpTaf {
this.rbac = rbac;
this.warn = turnOnWarning;
this.timeToLive = timeToLive;
+ String csvFile = access.getProperty(Config.CADI_BATH_CONVERT, null);
+ if(csvFile==null) {
+ mapIds=null;
+ } else {
+ try {
+ mapIds = new MapBathConverter(access, new CSV(csvFile));
+ } catch (IOException | CadiException e) {
+ access.log(e,"Bath Map Conversion is not initialzed (non fatal)");
+ }
+ }
}
public void add(final CredValDomain cvd) {
@@ -116,6 +131,9 @@ public class BasicHttpTaf implements HttpTaf {
if (warn&&!req.isSecure()) {
access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");
}
+ if(mapIds != null) {
+ authz = mapIds.convert(access, authz);
+ }
try {
CachedBasicPrincipal ba = new CachedBasicPrincipal(this,authz,realm,timeToLive);
if (DenialOfServiceTaf.isDeniedID(ba.getName())!=null) {
diff --git a/cadi/core/src/main/java/org/onap/aaf/cadi/util/CSV.java b/cadi/core/src/main/java/org/onap/aaf/cadi/util/CSV.java
new file mode 100644
index 00000000..4ae68310
--- /dev/null
+++ b/cadi/core/src/main/java/org/onap/aaf/cadi/util/CSV.java
@@ -0,0 +1,190 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T 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.aaf.cadi.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.aaf.cadi.CadiException;
+
+/**
+ * Read CSV file for various purposes
+ *
+ * @author Instrumental(Jonathan)
+ *
+ */
+public class CSV {
+ private File csv;
+
+ public CSV(File file) {
+ csv = file;
+ }
+
+ public CSV(String csvOfProperties) {
+ csv = new File(csvOfProperties);
+ }
+
+
+ /**
+ * Create your code to accept the List<String> row.
+ *
+ * Your code may keep the List... CSV does not hold onto it.
+ *
+ * @author Instrumental(Jonathan)
+ *
+ */
+ public interface Visitor {
+ void visit(List<String> row) throws IOException, CadiException;
+ }
+
+ public void visit(Visitor visitor) throws IOException, CadiException {
+ BufferedReader br = new BufferedReader(new FileReader(csv));
+ try {
+ String line;
+ StringBuilder sb = new StringBuilder();
+ while((line = br.readLine())!=null) {
+ line=line.trim();
+ if(!line.startsWith("#") && line.length()>0) {
+// System.out.println(line); uncomment to debug
+ List<String> row = new ArrayList<>();
+ boolean quotes=false;
+ boolean escape=false;
+ char c;
+ for(int i=0;i<line.length();++i) {
+ switch(c=line.charAt(i)) {
+ case '"':
+ if(quotes) {
+ if(i<line.length()-1) { // may look ahead
+ if('"' == line.charAt(i+1)) {
+ sb.append(c);
+ ++i;
+ } else {
+ quotes = false;
+ }
+ } else {
+ quotes=false;
+ }
+ } else {
+ quotes=true;
+ }
+ break;
+ case '\\':
+ if(escape) {
+ sb.append(c);
+ escape = false;
+ } else {
+ escape = true;
+ }
+ break;
+ case ',':
+ if(quotes) {
+ sb.append(c);
+ } else {
+ row.add(sb.toString());
+ sb.setLength(0);
+ }
+ break;
+ default:
+ sb.append(c);
+ }
+ }
+ if(sb.length()>0) {
+ row.add(sb.toString());
+ sb.setLength(0);
+ }
+ visitor.visit(row);
+ }
+ }
+ } finally {
+ br.close();
+ }
+ }
+
+ public Writer writer() throws FileNotFoundException {
+ return new Writer();
+ }
+
+ public class Writer {
+ private PrintStream ps;
+ private Writer() throws FileNotFoundException {
+ ps = new PrintStream(new FileOutputStream(csv));
+ }
+ public void row(Object ... strings) {
+ if(strings.length>0) {
+ boolean first = true;
+ boolean quote;
+ String s;
+ for(Object o : strings) {
+ if(first) {
+ first = false;
+ } else {
+ ps.append(',');
+ }
+ s = o.toString();
+ quote = s.matches(".*[,|\"].*");
+ if(quote) {
+ ps.append('"');
+ ps.print(s.replace("\"", "\"\"")
+ .replace("'", "''")
+ .replace("\\", "\\\\"));
+ ps.append('"');
+ } else {
+ ps.append(s);
+ }
+ }
+ ps.println();
+ }
+ }
+
+ /**
+ * Note: CSV files do not actually support Comments as a standard, but it is useful
+ * @param comment
+ */
+ public void comment(String comment) {
+ ps.print("# ");
+ ps.println(comment);
+ }
+
+ public void flush() {
+ ps.flush();
+ }
+
+ public void close() {
+ ps.close();
+ }
+ }
+
+ public void delete() {
+ csv.delete();
+ }
+
+ public String toString() {
+ return csv.getAbsolutePath();
+ }
+
+}
diff --git a/cadi/core/src/test/java/org/onap/aaf/cadi/config/test/JU_MapBathConverter.java b/cadi/core/src/test/java/org/onap/aaf/cadi/config/test/JU_MapBathConverter.java
new file mode 100644
index 00000000..0bfa94cb
--- /dev/null
+++ b/cadi/core/src/test/java/org/onap/aaf/cadi/config/test/JU_MapBathConverter.java
@@ -0,0 +1,217 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T 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.aaf.cadi.config.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.PropAccess;
+import org.onap.aaf.cadi.Symm;
+import org.onap.aaf.cadi.filter.MapBathConverter;
+import org.onap.aaf.cadi.util.CSV;
+import org.onap.aaf.cadi.util.CSV.Visitor;
+import org.onap.aaf.cadi.util.CSV.Writer;
+
+import junit.framework.Assert;
+
+/**
+ * Test a simple Migration conversion tool for CADI
+ *
+ * @author Instrumental(Jonathan)
+ *
+ */
+public class JU_MapBathConverter {
+ private static final String NEW_USER_SOMETHING_ORG = "NEW_USER@Something.org";
+ private static final String OLD_ID = "OLD_ID";
+ private static final String SHARED_PASS = "SHARED_PASS";
+ private static CSV csv;
+ private static ArrayList<String> expected;
+ private static final Access access = new PropAccess();
+ private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+
+ @BeforeClass
+ public static void createFile() throws IOException {
+ // Note, you cate a "MapBathConverter" by access to a File.
+ // We will create that file now. Local is fine.
+ csv = new CSV("JU_MapBathConverter.csv");
+ }
+
+ @BeforeClass
+ public static void beforeClass() {
+ expected = new ArrayList<>();
+ }
+
+ @Before
+ public void before() {
+ expected.clear();
+ }
+
+ @Test
+ public void test() throws IOException, CadiException {
+ CSV.Writer cw = csv.writer();
+ GregorianCalendar gc = new GregorianCalendar();
+ gc.add(GregorianCalendar.MONTH, 6);
+ try {
+ try {
+ // CSV can simply be OLD ID and NEW, no passwords
+ cw.row(exp(OLD_ID), exp(NEW_USER_SOMETHING_ORG),sdf.format(gc.getTime()));
+
+ // Style 1 - Incoming ID/pass, create new cred with NweID and same Pass
+ cw.row(exp(bath(OLD_ID,SHARED_PASS)), exp(NEW_USER_SOMETHING_ORG),sdf.format(gc.getTime()));
+ // the response should be Basic with NEW_ID and OLD_PASS
+
+ // Style 2
+ cw.row(exp(bath(OLD_ID,"OLD_PASS")), exp(bath(NEW_USER_SOMETHING_ORG,"NEW_PASS")),sdf.format(gc.getTime()));
+
+ } finally {
+ cw.close();
+ }
+
+ final Iterator<String> exp = expected.iterator();
+ csv.visit(new Visitor() {
+ @Override
+ public void visit(List<String> row) {
+ int i=0;
+ for(String s : row) {
+ switch(i++) {
+ case 0:
+ case 1:
+ Assert.assertEquals(exp.next(), s);
+ break;
+ case 2:
+ System.out.println(s);
+ break;
+ default:
+ Assert.fail("There should only be 3 columns in this test case.");
+ }
+ }
+ }
+ });
+
+ MapBathConverter mbc = new MapBathConverter(access, csv);
+
+ // Check no lookup just returns the same
+ Assert.assertEquals("NonKey", "NonKey"); // if not in map, expect same value
+
+ Iterator<String> exp1 = expected.iterator();
+ // there's no passwords in CSV
+ String old = exp1.next();
+ String nw = exp1.next();
+ Assert.assertEquals(nw, mbc.convert(access,old));
+
+ Assert.assertEquals(bath(NEW_USER_SOMETHING_ORG,SHARED_PASS), mbc.convert(access,bath(OLD_ID,SHARED_PASS)));
+
+ // Style 1 (new cred, old password)
+ old = exp1.next();
+ nw = bath(exp1.next(),SHARED_PASS);
+ Assert.assertEquals(nw, mbc.convert(access,old));
+
+ // Style 2
+ old = exp1.next();
+ nw = exp1.next();
+ Assert.assertEquals(nw, mbc.convert(access,old));
+
+ } finally {
+ csv.delete();
+ }
+ }
+
+ @Test
+ public void testTooFewColumns() throws IOException, CadiException {
+ CSV.Writer cw = csv.writer();
+ try {
+ try {
+ cw.row(exp(bath(OLD_ID,"OLD_PASS")), exp(bath(NEW_USER_SOMETHING_ORG,"NEW_PASS")));
+ } finally {
+ cw.close();
+ }
+
+ try {
+ new MapBathConverter(access, csv);
+ Assert.fail("file with too few rows should throw exception");
+ } catch(CadiException | IOException e) {
+ Assert.assertTrue("Correctly thrown Exception",true);
+ }
+ } finally {
+ csv.delete();
+ }
+ }
+
+ @Test
+ public void testNoFile() {
+ try {
+ new MapBathConverter(access, new CSV("Bogus"));
+ Assert.fail("Non Existent File should throw exception");
+ } catch(CadiException | IOException e) {
+ Assert.assertTrue("Correctly thrown Exception",true);
+ }
+ }
+
+ @Test
+ public void testBadRows() throws IOException {
+ try {
+ Writer cw = csv.writer();
+ try {
+ cw.row("Single Column");
+ } finally {
+ cw.close();
+ }
+
+ try {
+ new MapBathConverter(access,csv);
+ Assert.fail("Non Existent File should throw exception");
+ } catch(CadiException | IOException e) {
+ Assert.assertTrue("Correctly thrown Exception",true);
+ }
+ } finally {
+ csv.delete();
+ }
+
+ // Check for deletion
+ Assert.assertFalse(csv.toString() + "should have been deleted",new File(csv.toString()).exists());
+ }
+
+ private String bath(String user, String password) throws IOException {
+ StringBuilder sb = new StringBuilder(user);
+ sb.append(':');
+ sb.append(password);
+ byte[] encoded = Symm.base64noSplit.encode(sb.toString().getBytes());
+ sb.setLength(0);
+ sb.append("Basic ");
+ sb.append(new String(encoded));
+ return sb.toString();
+ }
+
+ private String exp(String s) {
+ expected.add(s);
+ return s;
+ }
+}
diff --git a/cadi/core/src/test/java/org/onap/aaf/cadi/util/test/JU_CSV.java b/cadi/core/src/test/java/org/onap/aaf/cadi/util/test/JU_CSV.java
new file mode 100644
index 00000000..54c48daf
--- /dev/null
+++ b/cadi/core/src/test/java/org/onap/aaf/cadi/util/test/JU_CSV.java
@@ -0,0 +1,122 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T 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.aaf.cadi.util.test;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.ws.Holder;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.util.CSV;
+import org.onap.aaf.cadi.util.CSV.Visitor;
+import org.onap.aaf.cadi.util.CSV.Writer;
+
+public class JU_CSV {
+
+ private String filename;
+ private File file;
+ private static ArrayList<Object> expected;
+
+ @Before
+ public void start() {
+ filename = "Sample.csv";
+ file = new File(filename);
+ }
+
+ @After
+ public void end() {
+ if(file!=null) {
+ file.delete();
+ }
+ }
+
+ @BeforeClass
+ public static void before() {
+ expected = new ArrayList<>();
+ }
+
+ @Test
+ public void test() throws IOException, CadiException {
+ CSV csv = new CSV(file);
+ // Can't visit for file that doesn't exist
+ try {
+ csv.visit(new Visitor() {
+ @Override
+ public void visit(List<String> row) {
+ }});
+ } catch(IOException e) {
+ Assert.assertTrue("CSV correctly created exception",true);
+ }
+
+ Writer writer = csv.writer();
+ try {
+ writer.row(add("\"hello\""));
+ writer.comment("Ignore Comments");
+ writer.row(add("dXNlcjpwYXNzd29yZA=="),add("dXNlckBzb21ldGhpbmcub3JnOm90aGVyUGFzc3dvcmQ="));
+ writer.row(); // no output
+ writer.row(add("There is, but one thing to say"), add(" and that is"), add("\"All the best\""));
+ } finally {
+ writer.close();
+ }
+
+ PrintStream garbage = new PrintStream(new FileOutputStream(file, true));
+ try {
+ garbage.println("# Ignore empty spaces, etc");
+ garbage.println(" ");
+ garbage.println("# Ignore blank lines");
+ garbage.println();
+ } finally {
+ garbage.close();
+ }
+
+
+ ////////////
+ // Tests
+ ////////////
+ final Holder<Integer> hi = new Holder<>(0);
+ csv.visit(new CSV.Visitor() {
+ @Override
+ public void visit(List<String> row) {
+ for(String s: row) {
+// System.out.println(hi.value + ") " + s);
+ Assert.assertEquals(expected.get(hi.value++),s);
+ }
+ }
+ });
+
+ }
+
+ private String add(String s) {
+ expected.add(s);
+ return s;
+ }
+
+}