AT&T 2.0.19 Code drop, stage 4
[aaf/authz.git] / authz-gui / src / main / java / com / att / authz / gui / pages / ApiDocs.java
1 package com.att.authz.gui.pages;
2
3 import java.io.IOException;
4 import java.net.ConnectException;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.Comparator;
8
9 import com.att.authz.env.AuthzTrans;
10 import com.att.authz.gui.AuthGUI;
11 import com.att.authz.gui.BreadCrumbs;
12 import com.att.authz.gui.NamedCode;
13 import com.att.authz.gui.Page;
14 import com.att.authz.gui.Table;
15 import com.att.authz.gui.Table.Cells;
16 import com.att.authz.gui.table.AbsCell;
17 import com.att.authz.gui.table.TextCell;
18 import org.onap.aaf.cadi.CadiException;
19 import org.onap.aaf.cadi.Symm;
20 import org.onap.aaf.cadi.client.Future;
21 import org.onap.aaf.cadi.client.Rcli;
22 import org.onap.aaf.cadi.client.Retryable;
23 import com.att.cssa.rserv.HttpMethods;
24 import org.onap.aaf.inno.env.APIException;
25 import org.onap.aaf.inno.env.Env;
26 import org.onap.aaf.inno.env.TimeTaken;
27 import com.att.xgen.Cache;
28 import com.att.xgen.html.HTMLGen;
29
30 import aaf.v2_0.Api;
31 import aaf.v2_0.Api.Route;
32
33 public class ApiDocs extends Page {
34         // Package on purpose
35         private static final String HREF = "/gui/api";
36         private static final String NAME = "AAF RESTful API";
37         private static final String fields[] = {};
38         private static final String ERROR_LINK = "<a href=\"./example/"
39                         + "YXBwbGljYXRpb24vRXJyb3IranNvbg=="
40 //                      + Symm.base64noSplit().encode("application/Error+json") 
41                         + "\">JSON</a> "
42                         + "<a href=\"./example/"
43                         + "YXBwbGljYXRpb24vRXJyb3IreG1s"
44 //                      + Symm.base64noSplit().encode("application/Error+xml") 
45                         + "\">XML</a> ";
46
47         
48         public ApiDocs(final AuthGUI gui, final Page ... breadcrumbs) throws APIException, IOException {
49                 super(gui.env,NAME,HREF, fields,
50                         new BreadCrumbs(breadcrumbs),
51                         new Preamble(),
52                         new Table<AuthGUI,AuthzTrans>("AAF API Reference",gui.env.newTransNoAvg(),new Model(), "class=std")
53                         );
54         }
55         
56         private static class Preamble extends NamedCode {
57
58                 private static final String I = "i";
59
60                 public Preamble() {
61                         super(false, "preamble");
62                 }
63
64                 @Override
65                 public void code(Cache<HTMLGen> cache, HTMLGen xgen) throws APIException, IOException {
66                         xgen.leaf(HTMLGen.H1).text("AAF 2.0 RESTful interface").end()
67                                 .hr();
68                         xgen.leaf(HTMLGen.H2).text("Accessing RESTful").end();
69                         xgen.incr(HTMLGen.UL)
70                                         .leaf(HTMLGen.LI).text("AAF RESTful service is secured by the following:").end()
71                                         .incr(HTMLGen.UL)
72                                                 .leaf(HTMLGen.LI).text("The Client must utilize HTTP/S. Non Secure HTTP is not acceptable").end()
73                                                 .leaf(HTMLGen.LI).text("The Client MUST supply an Identity validated by one of the following mechanisms").end()
74                                                 .incr(HTMLGen.UL)
75                                                         .leaf(HTMLGen.LI).text("(Near Future) Application level Certificate").end()
76                                                 .end()
77                                         .end()
78                                         .leaf(HTMLGen.LI).text("Responses").end()
79                                         .incr(HTMLGen.UL)
80                                                 .leaf(HTMLGen.LI).text("Each API Entity listed shows what structure will be accepted by service (ContentType) "
81                                                                 + "or responded with by service (Accept). Therefore, use these in making your call. Critical for PUT/POST.").end()
82                                                 .leaf(HTMLGen.LI).text("Each API call may respond with JSON or XML.  Choose the ContentType/Accept that has "
83                                                                 + "+json after the type for JSON or +xml after the Type for XML").end()
84                                                 .leaf(HTMLGen.LI).text("XSDs for Versions").end()
85                                                 .incr(HTMLGen.UL)
86                                                         .leaf(HTMLGen.LI).leaf(HTMLGen.A,"href=../theme/aaf_2_0.xsd").text("API 2.0").end().end()
87                                                 .end()
88                                                 .leaf(HTMLGen.LI).text("AAF can support multiple Versions of the API.  Choose the ContentType/Accept that has "
89                                                                 + "the appropriate version=?.?").end()
90                                                 .leaf(HTMLGen.LI).text("All Errors coming from AAF return AT&T Standard Error Message as a String: " + ERROR_LINK 
91                                                                 + " (does not apply to errors from Container)").end()
92                                         .end()
93                                         .leaf(HTMLGen.LI).text("Character Restrictions").end()
94                                         .incr(HTMLGen.UL)
95                                                 .leaf(HTMLGen.LI).text("Character Restrictions must depend on the Enforcement Point used").end()
96                                                 .leaf(HTMLGen.LI).text("Most AAF usage will be AAF Enforcement Point Characters for Instance and Action are:")
97                                                         .br().br().leaf(I).text("a-zA-Z0-9,.()_-=%").end()
98                                                         .br().br().text("For Instance, you may declare a multi-dimensional key with : (colon) separator, example:").end()
99                                                         .br().leaf(I).text(":myCluster:myKeyspace").end()
100                                                         .br().br().text("The * (asterix) may be used as a wild-card by itself or within the multi-dimensional key, example:")
101                                                         .br().leaf(I).text(":myCluster:*").end()
102                                                         .br().br().text("The % (percent) character can be used as an Escape Character. Applications can use % followed by 2 hexadecimal "
103                                                                         + "digits to cover odd keys.  It is their code, however, which must translate.")
104                                                         .br().br().text("The = (equals) is allowed so that Applications can pass Base64 encodations of binary keys").end()
105                                                 .leaf(HTMLGen.LI).text("Ask for a Consultation on how these are typically used, or, if your tool is the only Enforcement Point, if set may be expanded").end()
106                                         .end()
107                                 .end();
108                         /*
109                         
110                         The Content is defined in the AAF XSD - TODO Add aaf.xsdâ€�;
111                         Character Restrictions
112
113                         URLs impose restrictions on characters which have specific meanings. This means you cannot have these characters in the Field Content you send
114                         â€œ#â€� is a â€œFragment URLâ€�, or anchor. Content after this Character is not sent. AAF cannot do anything about this… don’t use it.
115                         â€œ?=&â€�. These are used to delineate Parameters.
116                         â€œ/“ is used to separate fields
117                         */
118                 }
119                 
120         };
121         /**
122          * Implement the Table Content for Permissions by User
123          * 
124          *
125          */
126         private static class Model implements Table.Data<AuthGUI,AuthzTrans> {
127                 public static final String[] HEADERS = new String[] {"Entity","Method","Path Info","Description"};
128                 private static final TextCell BLANK = new TextCell("");
129         
130                 @Override
131                 public String[] headers() {
132                         return HEADERS;
133                 }
134                 
135                 @SuppressWarnings("unchecked")
136                 @Override
137                 public Cells get(final AuthGUI gui, final AuthzTrans trans) {
138                         ArrayList<AbsCell[]> ns = new ArrayList<AbsCell[]>();
139                         ArrayList<AbsCell[]> perms = new ArrayList<AbsCell[]>();
140                         ArrayList<AbsCell[]> roles = new ArrayList<AbsCell[]>();
141                         ArrayList<AbsCell[]> user = new ArrayList<AbsCell[]>();
142                         ArrayList<AbsCell[]> aafOnly = new ArrayList<AbsCell[]>();
143                         ArrayList<AbsCell[]> rv = new ArrayList<AbsCell[]>();
144                         
145         
146                         TimeTaken tt = trans.start("AAF APIs",Env.REMOTE);
147                         try {
148                                 gui.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {
149                                         @Override
150                                         public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
151                                                 Future<Api> fa = client.read("/api",gui.apiDF);
152                                                 if(fa.get(5000)) {
153                                                         tt.done();
154                                                         TimeTaken tt2 = trans.start("Load Data", Env.SUB);
155                                                         try {
156                                                                 if(fa.value!=null)for(Route r : fa.value.getRoute()) {
157                                                                         String path = r.getPath();
158                                                                         // Build info
159                                                                         StringBuilder desc = new StringBuilder();
160                         
161                                                                         desc.append("<p class=double>");
162                                                                         desc.append(r.getDesc());
163                                                                         
164                                                                         if(r.getComments().size()>0) {
165                                                                                 for(String ct : r.getComments()) {
166                                                                                         desc.append("</p><p class=api_comment>");
167                                                                                         desc.append(ct);
168                                                                                 }
169                                                                         }
170                         
171                                                                         if(r.getParam().size()>0) {
172                                                                                 desc.append("<hr><p class=api_label>Parameters</p>");
173                                                                                 
174                                                                                 for(String params : r.getParam()) {
175                                                                                         String param[] = params.split("\\s*\\|\\s*");
176                                                                                         desc.append("</p><p class=api_contentType>");
177                                                                                         desc.append(param[0]);
178                                                                                         desc.append(" : ");
179                                                                                         desc.append(param[1]);
180                                                                                         if("true".equalsIgnoreCase(param[2])) {
181                                                                                                 desc.append(" (Required)");
182                                                                                         }
183                                                                                 }
184                                                                         }
185                         
186                         
187                                                                         if(r.getExpected()!=0) {
188                                                                                 desc.append("</p><p class=api_label>Expected HTTP Code</p><p class=api_comment>");
189                                                                                 desc.append(r.getExpected());
190                                                                         } 
191                         
192                                                                         if(r.getExplicitErr().size()!=0) {
193                                                                                 desc.append("</p><p class=api_label>Explicit HTTP Error Codes</p><p class=api_comment>");
194                                                                                 boolean first = true;
195                                                                                 for(int ee : r.getExplicitErr()) {
196                                                                                         if(first) {
197                                                                                                 first = false;
198                                                                                         } else {
199                                                                                                 desc.append(", ");
200                                                                                         }
201                                                                                         desc.append(ee);
202                                                                                 }
203                                                                         }
204                         
205                                                                         desc.append("</p><p class=api_label>");
206                                                                         desc.append("GET".equals(r.getMeth())?"Accept:":"ContentType:");
207                                                                         Collections.sort(r.getContentType());
208                                                                         if(r.getPath().startsWith("/authn/basicAuth")) {
209                                                                                 desc.append("</p><p class=api_contentType>text/plain");
210                                                                         }
211                                                                         for(String ct : r.getContentType()) {
212                                                                                 if(ct.contains("version=2")) {
213                                                                                         desc.append("</p><p class=api_contentType><a href=\"./example/");
214                                                                                         try {
215                                                                                                 desc.append(Symm.base64noSplit.encode(ct));
216                                                                                         } catch (IOException e) {
217                                                                                                 throw new CadiException(e);
218                                                                                         }
219                                                                                         desc.append("\"/>");
220                                                                                         desc.append(ct);
221                                                                                         desc.append("</a>");
222                                                                                 }
223                                                                         }
224                                                                         desc.append("</p>");
225                                                                         
226                                                                         
227                                                                         AbsCell[] sa = new AbsCell[] {
228                                                                                 null,
229                                                                                 new TextCell(r.getMeth(),"class=right"),
230                                                                                 new TextCell(r.getPath()),
231                                                                                 new TextCell(desc.toString()),
232                                                                         };
233                         
234                                                                         if(path.startsWith("/authz/perm")) {
235                                                                                 sa[0] = perms.size()==0?new TextCell("PERMISSION"):BLANK;
236                                                                                 perms.add(sa);
237                                                                         } else if(path.startsWith("/authz/role") || path.startsWith("/authz/userRole")) {
238                                                                                 sa[0] = roles.size()==0?new TextCell("ROLE"):BLANK;
239                                                                                 roles.add(sa);
240                                                                         } else if(path.startsWith("/authz/ns")) {
241                                                                                 sa[0] = ns.size()==0?new TextCell("NAMESPACE"):BLANK;
242                                                                                 ns.add(sa);
243                                                                         } else if(path.startsWith("/authn/basicAuth") 
244                                                                                 || path.startsWith("/authn/validate")
245                                                                                 || path.startsWith("/authz/user")) {
246                                                                                 sa[0] = user.size()==0?new TextCell("USER"):BLANK;
247                                                                                 user.add(sa);
248                                                                         } else {
249                                                                                 sa[0] = aafOnly.size()==0?new TextCell("AAF ONLY"):BLANK;
250                                                                                 aafOnly.add(sa);
251                                                                         }
252                                                                 }
253                                                                 //TODO if(trans.fish(p))
254                                                                 prepare(rv, perms,roles,ns,user);
255                                                         } finally {
256                                                                 tt2.done();
257                                                         }
258                                                 } else {
259                                                         gui.writeError(trans, fa, null);
260                                                 }
261                                                 return null;
262                                         }
263                                 });
264                         } catch (Exception e) {
265                                 trans.error().log(e.getMessage());
266                         } finally {
267                                 tt.done();
268                         }
269                         
270                         return new Cells(rv,null);
271                 }
272
273                 @SuppressWarnings("unchecked")
274                 private void prepare(ArrayList<AbsCell[]> rv, ArrayList<AbsCell[]> ... all) {
275                         AbsCell lead;
276                         AbsCell[] row;
277                         for(ArrayList<AbsCell[]> al : all) {
278                                 if(al.size()>1) {
279                                         row = al.get(0);
280                                         lead = row[0];
281                                         row[0]=BLANK;
282                                         al.get(0).clone()[0]=BLANK;
283                                         Collections.sort(al, new Comparator<AbsCell[]>() {
284                                                 @Override
285                                                 public int compare(AbsCell[] ca1, AbsCell[] ca2) {
286                                                         int meth = ((TextCell)ca1[2]).name.compareTo(
287                                                                            ((TextCell)ca2[2]).name);
288                                                         if(meth == 0) {
289                                                                 return (HttpMethods.valueOf(((TextCell)ca1[1]).name).compareTo(
290                                                                                 HttpMethods.valueOf(((TextCell)ca2[1]).name)));
291                                                         } else { 
292                                                                 return meth;
293                                                         }
294                                                 }
295                                         });
296                                         // set new first row
297                                         al.get(0)[0]=lead;
298
299                                         rv.addAll(al);
300                                 }
301                         }
302                 }
303         }
304 }