Update project structure to org.onap.aaf
[aaf/authz.git] / authz-cmd / src / main / java / org / onap / aaf / cmd / Cmd.java
diff --git a/authz-cmd/src/main/java/org/onap/aaf/cmd/Cmd.java b/authz-cmd/src/main/java/org/onap/aaf/cmd/Cmd.java
new file mode 100644 (file)
index 0000000..3c7f4ac
--- /dev/null
@@ -0,0 +1,499 @@
+/*******************************************************************************\r
+ * ============LICENSE_START====================================================\r
+ * * org.onap.aaf\r
+ * * ===========================================================================\r
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
+ * * ===========================================================================\r
+ * * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * * you may not use this file except in compliance with the License.\r
+ * * You may obtain a copy of the License at\r
+ * * \r
+ *  *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * * \r
+ *  * Unless required by applicable law or agreed to in writing, software\r
+ * * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * * See the License for the specific language governing permissions and\r
+ * * limitations under the License.\r
+ * * ============LICENSE_END====================================================\r
+ * *\r
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
+ * *\r
+ ******************************************************************************/\r
+package org.onap.aaf.cmd;\r
+\r
+import java.io.PrintWriter;\r
+import java.io.StringReader;\r
+import java.sql.Date;\r
+import java.text.DateFormat;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Comparator;\r
+import java.util.GregorianCalendar;\r
+import java.util.List;\r
+import java.util.Stack;\r
+import java.util.concurrent.ConcurrentHashMap;\r
+\r
+import org.onap.aaf.cssa.rserv.HttpMethods;\r
+\r
+import org.onap.aaf.cadi.CadiException;\r
+import org.onap.aaf.cadi.LocatorException;\r
+import org.onap.aaf.cadi.client.Future;\r
+import org.onap.aaf.cadi.client.Rcli;\r
+import org.onap.aaf.cadi.client.Retryable;\r
+import org.onap.aaf.cadi.http.HMangr;\r
+import org.onap.aaf.inno.env.APIException;\r
+import org.onap.aaf.inno.env.Data.TYPE;\r
+import org.onap.aaf.inno.env.Env;\r
+import org.onap.aaf.inno.env.util.Chrono;\r
+import org.onap.aaf.rosetta.env.RosettaDF;\r
+import org.onap.aaf.rosetta.env.RosettaEnv;\r
+\r
+import aaf.v2_0.Error;\r
+import aaf.v2_0.History;\r
+import aaf.v2_0.History.Item;\r
+import aaf.v2_0.Request;\r
+\r
+\r
+public abstract class Cmd {\r
+       private static final String AAF_DEFAULT_REALM = "aaf_default_realm";\r
+       \r
+       private static final DateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");\r
+       protected static final String BLANK = "";\r
+       protected static final String COMMA = ","; // for use in splits\r
+\r
+       protected static final int lineLength = 80;\r
+\r
+       private final static String hformat = "%-23s %-5s %-20s %-35s\n";\r
+\r
+       public static final String STARTDATE = "startdate";\r
+       public static final String ENDDATE = "enddate";\r
+       \r
+       private String name;\r
+       private final Param[] params;\r
+       private int required;\r
+       protected final Cmd parent;\r
+       protected final List<Cmd> children;\r
+       private final ConcurrentHashMap<Class<?>,RosettaDF<?>> dfs = new ConcurrentHashMap<Class<?>,RosettaDF<?>>();\r
+       public final AAFcli aafcli;\r
+       protected Env env;\r
+\r
+       public Cmd(AAFcli aafcli, String name, Param ... params) {\r
+               this(aafcli,null, name,params);\r
+       }\r
+\r
+       public Cmd(Cmd parent, String name, Param ... params) {\r
+               this(parent.aafcli,parent, name,params);\r
+       }\r
+\r
+       Cmd(AAFcli aafcli, Cmd parent, String name, Param ... params) {\r
+               this.parent = parent;\r
+               this.aafcli = aafcli;\r
+               this.env = aafcli.env;\r
+               if(parent!=null) {\r
+                       parent.children.add(this);\r
+               }\r
+               children = new ArrayList<Cmd>();\r
+               this.params = params;\r
+               this.name = name;\r
+               required=0;\r
+               for(Param p : params) {\r
+                       if(p.required) {\r
+                               ++required;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public final int exec(int idx, String ... args) throws CadiException, APIException, LocatorException {\r
+               if(args.length-idx<required) {\r
+                       throw new CadiException(build(new StringBuilder("Too few args: "),null).toString());\r
+               }\r
+               return _exec(idx,args);\r
+       }\r
+       \r
+       protected abstract int _exec(int idx, final String ... args) throws CadiException, APIException, LocatorException;\r
+       \r
+       public void detailedHelp(int indent,StringBuilder sb) {\r
+       }\r
+\r
+       protected void detailLine(StringBuilder sb, int length, String s) {\r
+               multiChar(sb,length,' ',0);\r
+               sb.append(s);\r
+       }\r
+\r
+       public void apis(int indent,StringBuilder sb) {\r
+       }\r
+\r
+       protected void api(StringBuilder sb, int _indent, HttpMethods hmeth, String pathInfo, Class<?> cls,boolean head) {\r
+           int indent = _indent;\r
+           final String meth = hmeth.name();\r
+               if(head) {\r
+                       sb.append('\n');\r
+                       detailLine(sb,indent,"APIs:");\r
+               }\r
+               indent+=2;\r
+               multiChar(sb,indent,' ',0);\r
+               sb.append(meth);\r
+               sb.append(' ');\r
+               sb.append(pathInfo);\r
+               String cliString = aafcli.typeString(cls,true);\r
+               if(indent+meth.length()+pathInfo.length()+cliString.length()+2>80) {\r
+                       sb.append(" ...");\r
+                       multiChar(sb,indent+3+meth.length(),' ',0);\r
+               } else { // same line\r
+                       sb.append(' ');\r
+               }\r
+               sb.append(cliString);\r
+       }\r
+\r
+       protected void multiChar(StringBuilder sb, int length, char c, int indent) {\r
+               sb.append('\n');\r
+               for(int i=0;i<indent;++i)sb.append(' ');\r
+               for(int i=indent;i<length;++i)sb.append(c);\r
+       }\r
+\r
+       public StringBuilder build(StringBuilder sb, StringBuilder detail) {\r
+               if(name!=null) {\r
+                       sb.append(name);\r
+                       sb.append(' ');\r
+               }\r
+               int line = sb.lastIndexOf("\n")+1;\r
+               if(line<0) {\r
+                       line=0;\r
+               }\r
+               int indent = sb.length()-line;\r
+               for(Param p : params) {\r
+                       sb.append(p.required?'<':'[');\r
+                       sb.append(p.tag);\r
+                       sb.append(p.required?"> ": "] ");\r
+               }\r
+               \r
+               boolean first = true;\r
+               for(Cmd child : children) {\r
+                       if(first) {\r
+                               first = false;\r
+                       } else if(detail==null) {\r
+                               multiChar(sb,indent,' ',0);\r
+                       } else {\r
+                               // Write parents for Detailed Report\r
+                               Stack<String> stack = new Stack<String>();\r
+                               for(Cmd c = child.parent;c!=null;c=c.parent) {\r
+                                       if(c.name!=null) {\r
+                                               stack.push(c.name);\r
+                                       }\r
+                               }\r
+                               if(!stack.isEmpty()) {\r
+                                       sb.append("  ");\r
+                                       while(!stack.isEmpty()) {\r
+                                               sb.append(stack.pop());\r
+                                               sb.append(' ');\r
+                                       }\r
+                               }\r
+                       }\r
+                       child.build(sb,detail);\r
+                       if(detail!=null) {\r
+                               child.detailedHelp(4, detail);\r
+                               // If Child wrote something, then add, bracketing by lines\r
+                               if(detail.length()>0) {\r
+                                       multiChar(sb,80,'-',2);\r
+                                       sb.append(detail);\r
+                                       sb.append('\n');\r
+                                       multiChar(sb,80,'-',2);\r
+                                       sb.append('\n');\r
+                                       detail.setLength(0); // reuse\r
+                               } else {\r
+                                       sb.append('\n');\r
+                               }\r
+                       }\r
+               }\r
+               return sb;\r
+       }\r
+       \r
+       protected void error(Future<?> future) {\r
+               StringBuilder sb = new StringBuilder("Failed");\r
+               String desc = future.body();\r
+               int code = future.code();\r
+               if(desc==null || desc.length()==0) {\r
+                       withCode(sb,code);\r
+               } else if(desc.startsWith("{")) {\r
+                       StringReader sr = new StringReader(desc);\r
+                       try {\r
+                               // Note: 11-18-2013.  This rather convoluted Message Structure required by TSS Restful Specs, reflecting "Northbound" practices.\r
+                               Error err = getDF(Error.class).newData().in(TYPE.JSON).load(sr).asObject();\r
+                               sb.append(" [");\r
+                               sb.append(err.getMessageId());\r
+                               sb.append("]: ");\r
+                               String messageBody = err.getText();\r
+                               List<String> vars = err.getVariables();\r
+                               int pipe;\r
+                               for (int varCounter=0;varCounter<vars.size();) {\r
+                                       String var = vars.get(varCounter);\r
+                                       ++varCounter;\r
+                                       if (messageBody.indexOf("%" + varCounter) >= 0) {\r
+                                               if((pipe = var.indexOf('|'))>=0) {  // In AAF, we use a PIPE for Choice\r
+                                                       if (aafcli.isTest()) {\r
+                                                               String expiresStr = var.substring(pipe);\r
+                                                               var = var.replace(expiresStr, "[Placeholder]");\r
+                                                       } else {\r
+                                                               StringBuilder varsb = new StringBuilder(var);\r
+                                                               varsb.deleteCharAt(pipe);\r
+                                                               var = varsb.toString();\r
+                                                       }\r
+                                                       messageBody = messageBody.replace("%" + varCounter, varCounter-1 + ") " + var);\r
+                                               } else {\r
+                                                       messageBody = messageBody.replace("%" + varCounter, var);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               sb.append(messageBody);\r
+                       } catch (Exception e) {\r
+                               withCode(sb,code);\r
+                               sb.append(" (Note: Details cannot be obtained from Error Structure)");\r
+                       }\r
+               } else if(desc.startsWith("<html>")){ // Core Jetty, etc sends HTML for Browsers\r
+                       withCode(sb,code);\r
+               } else {\r
+                       sb.append(" with code ");\r
+                       sb.append(code);\r
+                       sb.append(", ");\r
+                       sb.append(desc);\r
+               }\r
+               pw().println(sb);\r
+       }\r
+\r
+       \r
+       private void withCode(StringBuilder sb, Integer code) {\r
+               sb.append(" with code ");\r
+               sb.append(code);\r
+               switch(code) {\r
+                       case 401:\r
+                               sb.append(" (HTTP Not Authenticated)");\r
+                               break;\r
+                       case 403:\r
+                               sb.append(" (HTTP Forbidden)");\r
+                               break;\r
+                       case 404:\r
+                               sb.append(" (HTTP Not Found)");\r
+                               break;\r
+                       default:\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Consistently set start and end dates from Requests (all derived from Request)\r
+        * @param req\r
+        */\r
+       protected void setStartEnd(Request req) {\r
+               // Set Start/End Dates, if exist\r
+               String str;\r
+               if((str = env.getProperty(Cmd.STARTDATE,null))!=null) {\r
+                       req.setStart(Chrono.timeStamp(Date.valueOf(str)));\r
+               }\r
+               \r
+               if((str = env.getProperty(Cmd.ENDDATE,null))!=null) {\r
+                       req.setEnd(Chrono.timeStamp(Date.valueOf(str)));\r
+               }\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       protected<T> RosettaDF<T> getDF(Class<T> cls) throws APIException {\r
+               RosettaDF<T> rdf = (RosettaDF<T>)dfs.get(cls);\r
+               if(rdf == null) {\r
+                       rdf = env().newDataFactory(cls);\r
+                       dfs.put(cls, rdf);\r
+               }\r
+               return rdf;\r
+       }\r
+\r
+       public void activity(History history, String header) {\r
+               if (history.getItem().isEmpty()) {\r
+                       int start = header.indexOf('[');\r
+                       if (start >= 0) {\r
+                               pw().println("No Activity Found for " + header.substring(start));\r
+                       }\r
+               } else {\r
+                       pw().println(header);\r
+                       for(int i=0;i<lineLength;++i)pw().print('-');\r
+                       pw().println();\r
+                                                               \r
+                       pw().format(hformat,"Date","Table","User","Memo");\r
+                       for(int i=0;i<lineLength;++i)pw().print('-');\r
+                       pw().println();\r
+       \r
+                       // Save Server time by Sorting locally\r
+                       List<Item> items = history.getItem();\r
+                       java.util.Collections.sort(items, new Comparator<Item>() {\r
+                               @Override\r
+                               public int compare(Item o1, Item o2) {\r
+                                       return o2.getTimestamp().compare(o1.getTimestamp());\r
+                               }\r
+                       });\r
+                       \r
+                       for(History.Item item : items) {\r
+                               GregorianCalendar gc = item.getTimestamp().toGregorianCalendar();\r
+                               pw().format(hformat,\r
+                                       dateFmt.format(gc.getTime()),\r
+                                       item.getTarget(),\r
+                                       item.getUser(),\r
+                                       item.getMemo());\r
+                       }\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Turn String Array into a | delimited String\r
+        * @param options\r
+        * @return\r
+        */\r
+       public static String optionsToString(String[] options) {\r
+               StringBuilder sb = new StringBuilder();\r
+               boolean first = true;\r
+               for(String s : options) {\r
+                       if(first) {\r
+                               first = false;\r
+                       } else {\r
+                               sb.append('|');\r
+                       }\r
+                       sb.append(s);\r
+               }\r
+               return sb.toString();\r
+       }\r
+       \r
+       /**\r
+        * return which index number the Option matches.\r
+        * \r
+        * throws an Exception if not part of this Option Set\r
+        * \r
+        * @param options\r
+        * @param test\r
+        * @return\r
+        * @throws Exception\r
+        */\r
+       public int whichOption(String[] options, String test) throws CadiException {\r
+               for(int i=0;i<options.length;++i) {\r
+                       if(options[i].equals(test)) {\r
+                               return i;\r
+                       }\r
+               }\r
+               throw new CadiException(build(new StringBuilder("Invalid Option: "),null).toString());\r
+       }\r
+\r
+       protected RosettaEnv env() {\r
+               return aafcli.env;\r
+       }\r
+\r
+       protected HMangr hman() {\r
+               return aafcli.hman;\r
+       }\r
+\r
+       public<RET> RET same(Retryable<RET> retryable) throws APIException, CadiException, LocatorException {\r
+               // We're storing in AAFCli, because we know it's always the same, and single threaded\r
+               if(aafcli.prevCall!=null) {\r
+                       retryable.item(aafcli.prevCall.item());\r
+                       retryable.lastClient=aafcli.prevCall.lastClient;\r
+               }\r
+               \r
+               RET ret = aafcli.hman.same(aafcli.ss,retryable);\r
+               \r
+               // Store last call in AAFcli, because Cmds are all different instances.\r
+               aafcli.prevCall = retryable;\r
+               return ret;\r
+       }\r
+\r
+       public<RET> RET all(Retryable<RET> retryable) throws APIException, CadiException, LocatorException {\r
+               this.setQueryParamsOn(retryable.lastClient);\r
+               return aafcli.hman.all(aafcli.ss,retryable);\r
+       }\r
+\r
+       public<RET> RET oneOf(Retryable<RET> retryable,String host) throws APIException, CadiException, LocatorException {\r
+               this.setQueryParamsOn(retryable.lastClient);\r
+               return aafcli.hman.oneOf(aafcli.ss,retryable,true,host);\r
+       }\r
+\r
+       protected PrintWriter pw() {\r
+               return AAFcli.pw;\r
+       }\r
+\r
+       public String getName() {\r
+               return name;\r
+       }\r
+       \r
+       public void reportHead(String ... str) {\r
+               pw().println();\r
+               boolean first = true;\r
+               int i=0;\r
+               for(String s : str) {\r
+                       if(first) {\r
+                               if(++i>1) {\r
+                                       first = false;\r
+                                       pw().print("[");\r
+                               }\r
+                       } else {\r
+                               pw().print("] [");\r
+                       }\r
+                       pw().print(s);\r
+               }\r
+               if(!first) {\r
+                       pw().print(']');\r
+               }\r
+               pw().println();\r
+               reportLine();\r
+       }\r
+       \r
+       public String reportColHead(String format, String ...  args) {\r
+               pw().format(format,(Object[])args);\r
+               reportLine();\r
+               return format;\r
+       }\r
+\r
+       public void reportLine() {\r
+               for(int i=0;i<lineLength;++i)pw().print('-');\r
+               pw().println();\r
+       }\r
+       \r
+       protected void setQueryParamsOn(Rcli<?> rcli) {\r
+               StringBuilder sb=null;\r
+               String force;\r
+               if((force=aafcli.forceString())!=null) {\r
+                       sb = new StringBuilder("force=");\r
+                       sb.append(force);\r
+               }\r
+               if(aafcli.addRequest()) {\r
+                       if(sb==null) {\r
+                               sb = new StringBuilder("request=true");\r
+                       } else {\r
+                               sb.append("&request=true");\r
+                       }\r
+               }\r
+               if(sb!=null && rcli!=null) {\r
+                       rcli.setQueryParams(sb.toString());\r
+               }\r
+       }\r
+//\r
+//     /**\r
+//      * If Force is set, will return True once only, then revert to "FALSE".\r
+//      *  \r
+//      * @return\r
+//      */\r
+//     protected String checkForce() {\r
+//             if(TRUE.equalsIgnoreCase(env.getProperty(FORCE, FALSE))) {\r
+//                     env.setProperty(FORCE, FALSE);\r
+//                     return "true";\r
+//             }\r
+//             return FALSE;\r
+//     }\r
+\r
+       public String toString() {\r
+               StringBuilder sb = new StringBuilder();\r
+               if(parent==null) { // ultimate parent\r
+                       build(sb,null);\r
+                       return sb.toString();\r
+               } else {\r
+                       return parent.toString();\r
+               }\r
+       }\r
+       \r
+       public String getOrgRealm() {\r
+               return env.getProperty(AAF_DEFAULT_REALM);\r
+       }\r
+}\r