Update the aai-common with the latest code
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / restcore / RESTAPI.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.openecomp.aai
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.aai.restcore;
22
23 import java.io.StringReader;
24 import java.io.UnsupportedEncodingException;
25 import java.net.URI;
26 import java.text.DateFormat;
27 import java.text.SimpleDateFormat;
28 import java.util.ArrayList;
29 import java.util.Date;
30 import java.util.List;
31
32 import javax.ws.rs.core.HttpHeaders;
33 import javax.ws.rs.core.MediaType;
34 import javax.ws.rs.core.Response;
35 import javax.ws.rs.core.UriInfo;
36 import javax.xml.bind.JAXBException;
37 import javax.xml.transform.stream.StreamSource;
38
39 import org.eclipse.persistence.dynamic.DynamicEntity;
40 import org.eclipse.persistence.jaxb.JAXBUnmarshaller;
41 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
42
43 import org.openecomp.aai.db.props.AAIProperties;
44 import org.openecomp.aai.dbmap.DBConnectionType;
45 import org.openecomp.aai.domain.model.AAIResource;
46 import org.openecomp.aai.exceptions.AAIException;
47 import org.openecomp.aai.introspection.Introspector;
48 import org.openecomp.aai.introspection.Loader;
49 import org.openecomp.aai.introspection.tools.CreateUUID;
50 import org.openecomp.aai.introspection.tools.DefaultFields;
51 import org.openecomp.aai.introspection.tools.InjectKeysFromURI;
52 import org.openecomp.aai.introspection.tools.IntrospectorValidator;
53 import org.openecomp.aai.introspection.tools.Issue;
54 import org.openecomp.aai.introspection.tools.RemoveNonVisibleProperty;
55 import org.openecomp.aai.logging.ErrorLogHelper;
56 import org.openecomp.aai.logging.LoggingContext;
57 import org.openecomp.aai.util.AAIConfig;
58 import org.openecomp.aai.util.AAIConstants;
59 import org.openecomp.aai.util.AAITxnLog;
60 import com.att.eelf.configuration.EELFLogger;
61 import com.att.eelf.configuration.EELFManager;
62 import com.google.common.base.Joiner;
63
64
65 /**
66  * Base class for AAI REST API classes.
67  * Provides method to validate header information
68  * TODO should authenticate caller and authorize them for the API they are calling
69  * TODO should store the transaction
70  
71  *
72  */
73 public class RESTAPI {
74         
75         private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RESTAPI.class);
76
77         protected final String COMPONENT = "aairest";
78
79         /**
80          * The Enum Action.
81          */
82         public enum Action {
83                 GET, PUT, POST, DELETE
84         };
85
86         
87         public AAITxnLog txn = null;
88
89         /**
90          * Gets the from app id.
91          *
92          * @param headers the headers
93          * @param logline the logline
94          * @return the from app id
95          * @throws AAIException the AAI exception
96          */
97         protected String getFromAppId(HttpHeaders headers) throws AAIException { 
98                 String fromAppId = null;
99                 if (headers != null) {
100                         List<String> fromAppIdHeader = headers.getRequestHeader("X-FromAppId");
101                         if (fromAppIdHeader != null) {
102                                 for (String fromAppIdValue : fromAppIdHeader) {
103                                         fromAppId = fromAppIdValue;
104                                 }
105                         } 
106                 }
107
108                 if (fromAppId == null) {
109                         throw new AAIException("AAI_4009");
110                 }
111
112                 LoggingContext.partnerName(fromAppId);
113
114                 return fromAppId;
115         }
116         
117         /**
118          * Gets the trans id.
119          *
120          * @param headers the headers
121          * @param logline the logline
122          * @return the trans id
123          * @throws AAIException the AAI exception
124          */
125         protected String getTransId(HttpHeaders headers) throws AAIException { 
126                 String transId = null;
127                 if (headers != null) {
128                         List<String> transIdHeader = headers.getRequestHeader("X-TransactionId");
129                         if (transIdHeader != null) {
130                                 for (String transIdValue : transIdHeader) {
131                                         transId = transIdValue;
132                                 }
133                         }
134                 }
135
136                 if (transId == null) {
137                         throw new AAIException("AAI_4010");
138                 }
139
140                 LoggingContext.requestId(transId);
141
142                 return transId;
143         }
144         
145         
146         /**
147          * Gen date.
148          *
149          * @return the string
150          */
151         protected String genDate() {
152                 Date date = new Date();
153                 DateFormat formatter = null;
154                 try {
155                         formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT));
156                 } catch (AAIException ex) {
157                         ErrorLogHelper.logException(ex);
158                 } finally {
159                         if (formatter == null) {
160                                 formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS");
161                         }
162                 }
163
164                 return formatter.format(date);
165         }
166
167         /**
168          * Gets the media type.
169          *
170          * @param mediaTypeList the media type list
171          * @return the media type
172          */
173         protected String getMediaType(List <MediaType> mediaTypeList) {
174                 String mediaType = MediaType.APPLICATION_JSON;  // json is the default    
175                 for (MediaType mt : mediaTypeList) {
176                         if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) {
177                                 mediaType = MediaType.APPLICATION_XML;
178                         } 
179                 }
180                 return mediaType;
181         }
182         
183
184         /**
185          * Log transaction.
186          *
187          * @param appId the app id
188          * @param tId the t id
189          * @param action the action
190          * @param input the input
191          * @param rqstTm the rqst tm
192          * @param respTm the resp tm
193          * @param request the request
194          * @param response the response
195          */
196         /*  ---------------- Log Transaction into HBase --------------------- */
197         public void logTransaction(     String appId, String tId, String action, 
198                         String input, String rqstTm, String respTm, String request, Response response) {        
199                 String respBuf = "";
200                 int status = 0;
201
202                 if (response != null && response.getEntity() != null) {         
203                         respBuf = response.getEntity().toString();
204                         status = response.getStatus();
205                 }
206                 logTransaction(appId, tId, action, input, rqstTm, respTm, request, respBuf, String.valueOf(status));
207         }
208         
209         /**
210          * Log transaction.
211          *
212          * @param appId the app id
213          * @param tId the t id
214          * @param action the action
215          * @param input the input
216          * @param rqstTm the rqst tm
217          * @param respTm the resp tm
218          * @param request the request
219          * @param respBuf the resp buf
220          * @param status the status
221          * @param logline the logline
222          */
223         public void logTransaction(     String appId, String tId, String action, 
224                         String input, String rqstTm, String respTm, String request, String respBuf, String status) {    
225                 try {
226                         // we only run this way if we're not doing it in the CXF interceptor
227                         if (!AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_INTERCEPTOR).equalsIgnoreCase("true")) {
228                                 if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_ENABLED).equalsIgnoreCase("true")) {
229                                         txn = new AAITxnLog(tId, appId);
230                                         // tid, status, rqstTm, respTm, srcId, rsrcId, rsrcType, rqstBuf, respBuf               
231                                         String hbtid = txn.put(tId, status, 
232                                                         rqstTm, respTm, appId, input, action, request, respBuf);
233
234                                         LOGGER.debug("HbTransId={}",hbtid);
235                                         LOGGER.debug("action={}",  action);
236                                         LOGGER.debug("urlin={}", input);
237                                 }
238
239                         }
240                 } catch (AAIException e) {
241                         // i think we do nothing
242                 }
243         }
244         
245         /* ----------helpers for common consumer actions ----------- */
246         
247         /**
248          * Sets the depth.
249          *
250          * @param depthParam the depth param
251          * @return the int
252          * @throws AAIException the AAI exception
253          */
254         protected int setDepth(String depthParam) throws AAIException {
255                 int depth = AAIProperties.MAXIMUM_DEPTH; //default 
256                 if (depthParam != null && depthParam.length() > 0 && !depthParam.equals("all")){
257                         try {
258                                 depth = Integer.valueOf(depthParam);
259                         } catch (Exception e) {
260                                 throw new AAIException("AAI_4016");
261                         }
262                 }
263                 return depth;
264         }
265
266         /**
267          * Consumer exception response generator.
268          *
269          * @param headers the headers
270          * @param info the info
271          * @param templateAction the template action
272          * @param e the e
273          * @return the response
274          */
275         protected Response consumerExceptionResponseGenerator(HttpHeaders headers, UriInfo info, HttpMethod templateAction, AAIException e) {
276                 ArrayList<String> templateVars = new ArrayList<String>();
277                 templateVars.add(templateAction.toString()); //GET, PUT, etc
278                 templateVars.add(info.getPath().toString());
279                 templateVars.addAll(e.getTemplateVars());
280
281                 return Response
282                                 .status(e.getErrorObject().getHTTPResponseCode())
283                                 .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging(headers.getAcceptableMediaTypes(), e, templateVars))
284                                 .build();
285         }
286         
287         /**
288          * Validate introspector.
289          *
290          * @param obj the obj
291          * @param loader the loader
292          * @param uri the uri
293          * @param validateRequired the validate required
294          * @throws AAIException the AAI exception
295          * @throws UnsupportedEncodingException the unsupported encoding exception
296          */
297         protected void validateIntrospector(Introspector obj, Loader loader, URI uri, HttpMethod method) throws AAIException, UnsupportedEncodingException {
298                 
299                 int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
300                 boolean validateRequired = true;
301                 if (method.equals(HttpMethod.MERGE_PATCH)) {
302                         validateRequired = false;
303                         maximumDepth = 0;
304                 }
305                 IntrospectorValidator validator = new IntrospectorValidator.Builder()
306                                 .validateRequired(validateRequired)
307                                 .restrictDepth(maximumDepth)
308                                 .addResolver(new RemoveNonVisibleProperty())
309                                 .addResolver(new CreateUUID())
310                                 .addResolver(new DefaultFields())
311                                 .addResolver(new InjectKeysFromURI(loader, uri))
312                                 .build();
313                 boolean result = validator.validate(obj);
314                 if (!result) {
315                         result = validator.resolveIssues();
316                 }
317                 if (!result) {
318                         List<String> messages = new ArrayList<>();
319                         for (Issue issue : validator.getIssues()) {
320                                 if (!issue.isResolved()) {
321                                         messages.add(issue.getDetail());
322                                 }
323                         }
324                         String errors = Joiner.on(",").join(messages);
325                         throw new AAIException("AAI_3000", errors);
326                 }
327                 //check that key in payload and key in request uri are the same
328         String objURI = obj.getURI();
329         //if requested object is a parent objURI will have a leading slash the input uri will lack
330         //this adds that leading slash for the comparison
331         String testURI = "/" + uri.getRawPath();
332         if (!testURI.endsWith(objURI)) {
333                 throw new AAIException("AAI_3000", "uri and payload keys don't match");
334         }
335         }
336         
337         protected DBConnectionType determineConnectionType(String fromAppId, String realTime) {
338                 DBConnectionType type = DBConnectionType.REALTIME;
339                 boolean isRealTimeClient = AAIConfig.get("aai.realtime.clients", "").contains(fromAppId);
340                 if (isRealTimeClient || realTime != null) {
341                         type = DBConnectionType.REALTIME;
342                 } else {
343                         type = DBConnectionType.CACHED;
344                 }
345                 
346                 return type;
347         }
348         
349         /**
350          * Gets the input media type.
351          *
352          * @param mediaType the media type
353          * @return the input media type
354          */
355         protected String getInputMediaType(MediaType mediaType) {
356                 String result = mediaType.getType() + "/" + mediaType.getSubtype();
357                 
358                 return result;
359                 
360         }
361
362 }