+++ /dev/null
-/*******************************************************************************\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