AT&T 2.0.19 Code drop, stage 4
[aaf/authz.git] / authz-gw / src / main / java / org / onap / aaf / authz / gw / facade / GwFacadeImpl.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aaf\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package org.onap.aaf.authz.gw.facade;\r
24 \r
25 \r
26 import static org.onap.aaf.authz.layer.Result.ERR_ActionNotCompleted;\r
27 import static org.onap.aaf.authz.layer.Result.ERR_BadData;\r
28 import static org.onap.aaf.authz.layer.Result.ERR_ConflictAlreadyExists;\r
29 import static org.onap.aaf.authz.layer.Result.ERR_Denied;\r
30 import static org.onap.aaf.authz.layer.Result.ERR_NotFound;\r
31 import static org.onap.aaf.authz.layer.Result.ERR_NotImplemented;\r
32 import static org.onap.aaf.authz.layer.Result.ERR_Policy;\r
33 import static org.onap.aaf.authz.layer.Result.ERR_Security;\r
34 \r
35 import java.lang.reflect.Method;\r
36 \r
37 import javax.servlet.http.HttpServletResponse;\r
38 \r
39 import org.onap.aaf.authz.env.AuthzEnv;\r
40 import org.onap.aaf.authz.env.AuthzTrans;\r
41 import org.onap.aaf.authz.gw.mapper.Mapper;\r
42 import org.onap.aaf.authz.gw.mapper.Mapper.API;\r
43 import org.onap.aaf.authz.gw.service.GwService;\r
44 import org.onap.aaf.authz.gw.service.GwServiceImpl;\r
45 import org.onap.aaf.authz.layer.FacadeImpl;\r
46 import org.onap.aaf.authz.layer.Result;\r
47 import org.onap.aaf.cssa.rserv.RServlet;\r
48 import org.onap.aaf.cssa.rserv.RouteReport;\r
49 import org.onap.aaf.cssa.rserv.doc.ApiDoc;\r
50 \r
51 import org.onap.aaf.cadi.aaf.client.Examples;\r
52 import org.onap.aaf.inno.env.APIException;\r
53 import org.onap.aaf.inno.env.Data;\r
54 import org.onap.aaf.inno.env.Data.TYPE;\r
55 import org.onap.aaf.inno.env.Env;\r
56 import org.onap.aaf.inno.env.TimeTaken;\r
57 import org.onap.aaf.rosetta.env.RosettaDF;\r
58 \r
59 import gw.v1_0.Api;\r
60 \r
61 /**\r
62  * AuthzFacade\r
63  * \r
64  * This Service Facade encapsulates the essence of the API Service can do, and provides\r
65  * a single created object for elements such as RosettaDF.\r
66  *\r
67  * The Responsibilities of this class are to:\r
68  * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage)\r
69  * 2) Validate incoming data (if applicable)\r
70  * 3) Convert the Service response into the right Format, and mark the Content Type\r
71  *              a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request.\r
72  * 4) Log Service info, warnings and exceptions as necessary\r
73  * 5) When asked by the API layer, this will create and write Error content to the OutputStream\r
74  * \r
75  * Note: This Class does NOT set the HTTP Status Code.  That is up to the API layer, so that it can be \r
76  * clearly coordinated with the API Documentation\r
77  * \r
78  *\r
79  */\r
80 public abstract class GwFacadeImpl<IN,OUT,ERROR> extends FacadeImpl implements GwFacade \r
81         {\r
82         private GwService<IN,OUT,ERROR> service;\r
83 \r
84         private final RosettaDF<ERROR>          errDF;\r
85         private final RosettaDF<Api>            apiDF;\r
86 \r
87         public GwFacadeImpl(AuthzEnv env, GwService<IN,OUT,ERROR> service, Data.TYPE dataType) throws APIException {\r
88                 this.service = service;\r
89                 (errDF                          = env.newDataFactory(mapper().getClass(API.ERROR))).in(dataType).out(dataType);\r
90                 (apiDF                          = env.newDataFactory(Api.class)).in(dataType).out(dataType);\r
91         }\r
92         \r
93         public Mapper<IN,OUT,ERROR> mapper() {\r
94                 return service.mapper();\r
95         }\r
96                 \r
97         /* (non-Javadoc)\r
98          * @see com.att.authz.facade.AuthzFacade#error(org.onap.aaf.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse, int)\r
99          * \r
100          * Note: Conforms to AT&T TSS RESTful Error Structure\r
101          */\r
102         @Override\r
103         public void error(AuthzTrans trans, HttpServletResponse response, Result<?> result) {\r
104                 String msg = result.details==null?"":result.details.trim();\r
105                 String[] detail;\r
106                 if(result.variables==null) {\r
107                         detail = new String[1];\r
108                 } else {\r
109                         int l = result.variables.length;\r
110                         detail=new String[l+1];\r
111                         System.arraycopy(result.variables, 0, detail, 1, l);\r
112                 }\r
113                 error(trans, response, result.status,msg,detail);\r
114         }\r
115                 \r
116         @Override\r
117         public void error(AuthzTrans trans, HttpServletResponse response, int status, String msg, String ... _detail) {\r
118                 String[] detail = _detail;\r
119                 if(detail.length==0) {\r
120                     detail=new String[1];\r
121                 }\r
122                 String msgId;\r
123                 switch(status) {\r
124                         case 202:\r
125                         case ERR_ActionNotCompleted:\r
126                                 msgId = "SVC1202";\r
127                                 detail[0] = "Accepted, Action not complete";\r
128                                 response.setStatus(/*httpstatus=*/202);\r
129                                 break;\r
130 \r
131                         case 403:\r
132                         case ERR_Policy:\r
133                         case ERR_Security:\r
134                         case ERR_Denied:\r
135                                 msgId = "SVC1403";\r
136                                 detail[0] = "Forbidden";\r
137                                 response.setStatus(/*httpstatus=*/403);\r
138                                 break;\r
139                                 \r
140                         case 404:\r
141                         case ERR_NotFound:\r
142                                 msgId = "SVC1404";\r
143                                 detail[0] = "Not Found";\r
144                                 response.setStatus(/*httpstatus=*/404);\r
145                                 break;\r
146 \r
147                         case 406:\r
148                         case ERR_BadData:\r
149                                 msgId="SVC1406";\r
150                                 detail[0] = "Not Acceptable";\r
151                                 response.setStatus(/*httpstatus=*/406);\r
152                                 break;\r
153                                 \r
154                         case 409:\r
155                         case ERR_ConflictAlreadyExists:\r
156                                 msgId = "SVC1409";\r
157                                 detail[0] = "Conflict Already Exists";\r
158                                 response.setStatus(/*httpstatus=*/409);\r
159                                 break;\r
160                         \r
161                         case 501:\r
162                         case ERR_NotImplemented:\r
163                                 msgId = "SVC1501";\r
164                                 detail[0] = "Not Implemented"; \r
165                                 response.setStatus(/*httpstatus=*/501);\r
166                                 break;\r
167                                 \r
168 \r
169                         default:\r
170                                 msgId = "SVC1500";\r
171                                 detail[0] = "General Service Error";\r
172                                 response.setStatus(/*httpstatus=*/500);\r
173                                 break;\r
174                 }\r
175 \r
176                 try {\r
177                         StringBuilder holder = new StringBuilder();\r
178                         errDF.newData(trans).load(\r
179                                 mapper().errorFromMessage(holder,msgId,msg,detail)).to(response.getOutputStream());\r
180                         trans.checkpoint(\r
181                                         "ErrResp [" + \r
182                                         msgId +\r
183                                         "] " +\r
184                                         holder.toString(),\r
185                                         Env.ALWAYS);\r
186                 } catch (Exception e) {\r
187                         trans.error().log(e,"unable to send response for",msg);\r
188                 }\r
189         }\r
190         \r
191         /* (non-Javadoc)\r
192          * @see com.att.authz.facade.AuthzFacade#getAPI(org.onap.aaf.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse)\r
193          */\r
194         public final static String API_REPORT = "apiReport";\r
195         @Override\r
196         public Result<Void> getAPI(AuthzTrans trans, HttpServletResponse resp, RServlet<AuthzTrans> rservlet) {\r
197                 TimeTaken tt = trans.start(API_REPORT, Env.SUB);\r
198                 try {\r
199                         Api api = new Api();\r
200                         Api.Route ar;\r
201                         Method[] meths = GwServiceImpl.class.getDeclaredMethods();\r
202                         for(RouteReport rr : rservlet.routeReport()) {\r
203                                 api.getRoute().add(ar = new Api.Route());\r
204                                 ar.setMeth(rr.meth.name());\r
205                                 ar.setPath(rr.path);\r
206                                 ar.setDesc(rr.desc);\r
207                                 ar.getContentType().addAll(rr.contextTypes);\r
208                                 for(Method m : meths) {\r
209                                         ApiDoc ad;\r
210                                         if((ad = m.getAnnotation(ApiDoc.class))!=null &&\r
211                                                         rr.meth.equals(ad.method()) &&\r
212                                                     rr.path.equals(ad.path())) {\r
213                                                 for(String param : ad.params()) {\r
214                                                         ar.getParam().add(param);\r
215                                                 }\r
216                                                 for(String text : ad.text()) {\r
217                                                         ar.getComments().add(text);\r
218                                                 }\r
219                                                 ar.setExpected(ad.expectedCode());\r
220                                                 for(int ec : ad.errorCodes()) {\r
221                                                         ar.getExplicitErr().add(ec);\r
222                                                 }\r
223                                         }\r
224                                 }\r
225                         }\r
226                         apiDF.newData(trans).load(api).to(resp.getOutputStream());\r
227                         setContentType(resp,apiDF.getOutType());\r
228                         return Result.ok();\r
229 \r
230                 } catch (Exception e) {\r
231                         trans.error().log(e,IN,API_REPORT);\r
232                         return Result.err(e);\r
233                 } finally {\r
234                         tt.done();\r
235                 }\r
236         }\r
237         \r
238         public final static String API_EXAMPLE = "apiExample";\r
239         /* (non-Javadoc)\r
240          * @see com.att.authz.facade.AuthzFacade#getAPIExample(org.onap.aaf.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse, java.lang.String)\r
241          */\r
242         @Override\r
243         public Result<Void> getAPIExample(AuthzTrans trans, HttpServletResponse resp, String nameOrContentType, boolean optional) {\r
244                 TimeTaken tt = trans.start(API_EXAMPLE, Env.SUB);\r
245                 try {\r
246                         String content =Examples.print(apiDF.getEnv(), nameOrContentType, optional); \r
247                         resp.getOutputStream().print(content);\r
248                         setContentType(resp,content.contains("<?xml")?TYPE.XML:TYPE.JSON);\r
249                         return Result.ok();\r
250                 } catch (Exception e) {\r
251                         trans.error().log(e,IN,API_EXAMPLE);\r
252                         return Result.err(Result.ERR_NotImplemented,e.getMessage());\r
253                 } finally {\r
254                         tt.done();\r
255                 }\r
256         }\r
257 \r
258 }\r