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