--- /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.authz.gw.facade;\r
+\r
+\r
+import static org.onap.aaf.authz.layer.Result.ERR_ActionNotCompleted;\r
+import static org.onap.aaf.authz.layer.Result.ERR_BadData;\r
+import static org.onap.aaf.authz.layer.Result.ERR_ConflictAlreadyExists;\r
+import static org.onap.aaf.authz.layer.Result.ERR_Denied;\r
+import static org.onap.aaf.authz.layer.Result.ERR_NotFound;\r
+import static org.onap.aaf.authz.layer.Result.ERR_NotImplemented;\r
+import static org.onap.aaf.authz.layer.Result.ERR_Policy;\r
+import static org.onap.aaf.authz.layer.Result.ERR_Security;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import org.onap.aaf.authz.env.AuthzEnv;\r
+import org.onap.aaf.authz.env.AuthzTrans;\r
+import org.onap.aaf.authz.gw.mapper.Mapper;\r
+import org.onap.aaf.authz.gw.mapper.Mapper.API;\r
+import org.onap.aaf.authz.gw.service.GwService;\r
+import org.onap.aaf.authz.gw.service.GwServiceImpl;\r
+import org.onap.aaf.authz.layer.FacadeImpl;\r
+import org.onap.aaf.authz.layer.Result;\r
+import org.onap.aaf.cssa.rserv.RServlet;\r
+import org.onap.aaf.cssa.rserv.RouteReport;\r
+import org.onap.aaf.cssa.rserv.doc.ApiDoc;\r
+\r
+import org.onap.aaf.cadi.aaf.client.Examples;\r
+import org.onap.aaf.inno.env.APIException;\r
+import org.onap.aaf.inno.env.Data;\r
+import org.onap.aaf.inno.env.Data.TYPE;\r
+import org.onap.aaf.inno.env.Env;\r
+import org.onap.aaf.inno.env.TimeTaken;\r
+import org.onap.aaf.rosetta.env.RosettaDF;\r
+\r
+import gw.v1_0.Api;\r
+\r
+/**\r
+ * AuthzFacade\r
+ * \r
+ * This Service Facade encapsulates the essence of the API Service can do, and provides\r
+ * a single created object for elements such as RosettaDF.\r
+ *\r
+ * The Responsibilities of this class are to:\r
+ * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage)\r
+ * 2) Validate incoming data (if applicable)\r
+ * 3) Convert the Service response into the right Format, and mark the Content Type\r
+ * a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request.\r
+ * 4) Log Service info, warnings and exceptions as necessary\r
+ * 5) When asked by the API layer, this will create and write Error content to the OutputStream\r
+ * \r
+ * Note: This Class does NOT set the HTTP Status Code. That is up to the API layer, so that it can be \r
+ * clearly coordinated with the API Documentation\r
+ * \r
+ *\r
+ */\r
+public abstract class GwFacadeImpl<IN,OUT,ERROR> extends FacadeImpl implements GwFacade \r
+ {\r
+ private GwService<IN,OUT,ERROR> service;\r
+\r
+ private final RosettaDF<ERROR> errDF;\r
+ private final RosettaDF<Api> apiDF;\r
+\r
+ public GwFacadeImpl(AuthzEnv env, GwService<IN,OUT,ERROR> service, Data.TYPE dataType) throws APIException {\r
+ this.service = service;\r
+ (errDF = env.newDataFactory(mapper().getClass(API.ERROR))).in(dataType).out(dataType);\r
+ (apiDF = env.newDataFactory(Api.class)).in(dataType).out(dataType);\r
+ }\r
+ \r
+ public Mapper<IN,OUT,ERROR> mapper() {\r
+ return service.mapper();\r
+ }\r
+ \r
+ /* (non-Javadoc)\r
+ * @see com.att.authz.facade.AuthzFacade#error(org.onap.aaf.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse, int)\r
+ * \r
+ * Note: Conforms to AT&T TSS RESTful Error Structure\r
+ */\r
+ @Override\r
+ public void error(AuthzTrans trans, HttpServletResponse response, Result<?> result) {\r
+ String msg = result.details==null?"":result.details.trim();\r
+ String[] detail;\r
+ if(result.variables==null) {\r
+ detail = new String[1];\r
+ } else {\r
+ int l = result.variables.length;\r
+ detail=new String[l+1];\r
+ System.arraycopy(result.variables, 0, detail, 1, l);\r
+ }\r
+ error(trans, response, result.status,msg,detail);\r
+ }\r
+ \r
+ @Override\r
+ public void error(AuthzTrans trans, HttpServletResponse response, int status, String msg, String ... _detail) {\r
+ String[] detail = _detail;\r
+ if(detail.length==0) {\r
+ detail=new String[1];\r
+ }\r
+ String msgId;\r
+ switch(status) {\r
+ case 202:\r
+ case ERR_ActionNotCompleted:\r
+ msgId = "SVC1202";\r
+ detail[0] = "Accepted, Action not complete";\r
+ response.setStatus(/*httpstatus=*/202);\r
+ break;\r
+\r
+ case 403:\r
+ case ERR_Policy:\r
+ case ERR_Security:\r
+ case ERR_Denied:\r
+ msgId = "SVC1403";\r
+ detail[0] = "Forbidden";\r
+ response.setStatus(/*httpstatus=*/403);\r
+ break;\r
+ \r
+ case 404:\r
+ case ERR_NotFound:\r
+ msgId = "SVC1404";\r
+ detail[0] = "Not Found";\r
+ response.setStatus(/*httpstatus=*/404);\r
+ break;\r
+\r
+ case 406:\r
+ case ERR_BadData:\r
+ msgId="SVC1406";\r
+ detail[0] = "Not Acceptable";\r
+ response.setStatus(/*httpstatus=*/406);\r
+ break;\r
+ \r
+ case 409:\r
+ case ERR_ConflictAlreadyExists:\r
+ msgId = "SVC1409";\r
+ detail[0] = "Conflict Already Exists";\r
+ response.setStatus(/*httpstatus=*/409);\r
+ break;\r
+ \r
+ case 501:\r
+ case ERR_NotImplemented:\r
+ msgId = "SVC1501";\r
+ detail[0] = "Not Implemented"; \r
+ response.setStatus(/*httpstatus=*/501);\r
+ break;\r
+ \r
+\r
+ default:\r
+ msgId = "SVC1500";\r
+ detail[0] = "General Service Error";\r
+ response.setStatus(/*httpstatus=*/500);\r
+ break;\r
+ }\r
+\r
+ try {\r
+ StringBuilder holder = new StringBuilder();\r
+ errDF.newData(trans).load(\r
+ mapper().errorFromMessage(holder,msgId,msg,detail)).to(response.getOutputStream());\r
+ trans.checkpoint(\r
+ "ErrResp [" + \r
+ msgId +\r
+ "] " +\r
+ holder.toString(),\r
+ Env.ALWAYS);\r
+ } catch (Exception e) {\r
+ trans.error().log(e,"unable to send response for",msg);\r
+ }\r
+ }\r
+ \r
+ /* (non-Javadoc)\r
+ * @see com.att.authz.facade.AuthzFacade#getAPI(org.onap.aaf.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse)\r
+ */\r
+ public final static String API_REPORT = "apiReport";\r
+ @Override\r
+ public Result<Void> getAPI(AuthzTrans trans, HttpServletResponse resp, RServlet<AuthzTrans> rservlet) {\r
+ TimeTaken tt = trans.start(API_REPORT, Env.SUB);\r
+ try {\r
+ Api api = new Api();\r
+ Api.Route ar;\r
+ Method[] meths = GwServiceImpl.class.getDeclaredMethods();\r
+ for(RouteReport rr : rservlet.routeReport()) {\r
+ api.getRoute().add(ar = new Api.Route());\r
+ ar.setMeth(rr.meth.name());\r
+ ar.setPath(rr.path);\r
+ ar.setDesc(rr.desc);\r
+ ar.getContentType().addAll(rr.contextTypes);\r
+ for(Method m : meths) {\r
+ ApiDoc ad;\r
+ if((ad = m.getAnnotation(ApiDoc.class))!=null &&\r
+ rr.meth.equals(ad.method()) &&\r
+ rr.path.equals(ad.path())) {\r
+ for(String param : ad.params()) {\r
+ ar.getParam().add(param);\r
+ }\r
+ for(String text : ad.text()) {\r
+ ar.getComments().add(text);\r
+ }\r
+ ar.setExpected(ad.expectedCode());\r
+ for(int ec : ad.errorCodes()) {\r
+ ar.getExplicitErr().add(ec);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ apiDF.newData(trans).load(api).to(resp.getOutputStream());\r
+ setContentType(resp,apiDF.getOutType());\r
+ return Result.ok();\r
+\r
+ } catch (Exception e) {\r
+ trans.error().log(e,IN,API_REPORT);\r
+ return Result.err(e);\r
+ } finally {\r
+ tt.done();\r
+ }\r
+ }\r
+ \r
+ public final static String API_EXAMPLE = "apiExample";\r
+ /* (non-Javadoc)\r
+ * @see com.att.authz.facade.AuthzFacade#getAPIExample(org.onap.aaf.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse, java.lang.String)\r
+ */\r
+ @Override\r
+ public Result<Void> getAPIExample(AuthzTrans trans, HttpServletResponse resp, String nameOrContentType, boolean optional) {\r
+ TimeTaken tt = trans.start(API_EXAMPLE, Env.SUB);\r
+ try {\r
+ String content =Examples.print(apiDF.getEnv(), nameOrContentType, optional); \r
+ resp.getOutputStream().print(content);\r
+ setContentType(resp,content.contains("<?xml")?TYPE.XML:TYPE.JSON);\r
+ return Result.ok();\r
+ } catch (Exception e) {\r
+ trans.error().log(e,IN,API_EXAMPLE);\r
+ return Result.err(Result.ERR_NotImplemented,e.getMessage());\r
+ } finally {\r
+ tt.done();\r
+ }\r
+ }\r
+\r
+}\r