79b54660723d6db6a1040406e4b86ff8275677be
[aai/sparky-be.git] / src / main / java / org / onap / aai / sparky / editattributes / AttributeUpdater.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 Amdocs
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21 package org.onap.aai.sparky.editattributes;
22
23 import java.net.URI;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
29
30 import javax.ws.rs.core.UriBuilder;
31
32 import org.eclipse.persistence.dynamic.DynamicType;
33 import org.onap.aai.cl.api.Logger;
34 import org.onap.aai.cl.eelf.LoggerFactory;
35 import org.onap.aai.restclient.client.OperationResult;
36 import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
37 import org.onap.aai.sparky.config.oxm.OxmModelLoader;
38 import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
39 import org.onap.aai.sparky.editattributes.exception.AttributeUpdateException;
40 import org.onap.aai.sparky.logging.AaiUiMsgs;
41
42 import com.fasterxml.jackson.core.JsonProcessingException;
43 import com.fasterxml.jackson.databind.ObjectMapper;
44 import com.fasterxml.jackson.databind.ObjectWriter;
45 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
46
47 /**
48  * Class to process attribute updates on AAI objects.
49  *
50  *
51  */
52 public class AttributeUpdater {
53   
54   /**
55    * The Class AaiEditObject.
56    */
57   public class AaiEditObject {
58     String objectType;
59     String rootElement;
60     String keyName;
61     String keyValue;
62     String schemaVersion;
63
64     /**
65      * Instantiates a new aai edit object.
66      */
67     public AaiEditObject() {
68
69     }
70
71     /**
72      * Instantiates a new aai edit object.
73      *
74      * @param objectType the object type
75      * @param idName the id name
76      * @param schemaVersion the schema version
77      */
78     public AaiEditObject(String objectType, String idName, String schemaVersion) {
79       super();
80       this.objectType = objectType;
81       this.keyName = idName;
82       this.schemaVersion = schemaVersion;
83     }
84
85     public String getObjectType() {
86       return objectType;
87     }
88
89     public void setObjectType(String objectType) {
90       this.objectType = objectType;
91     }
92
93     public String getKeyName() {
94       return keyName;
95     }
96
97     public void setKeyName(String idName) {
98       this.keyName = idName;
99     }
100
101     public String getSchemaVersion() {
102       return schemaVersion;
103     }
104
105     public void setSchemaVersion(String schemaVersion) {
106       this.schemaVersion = schemaVersion;
107     }
108
109     public void setKeyValue(String keyValue) {
110       this.keyValue = keyValue;
111     }
112
113     public String getKeyValue() {
114       return keyValue;
115     }
116
117     public String getRootElement() {
118       return rootElement;
119     }
120
121     public void setRootElement(String rootElement) {
122       this.rootElement = rootElement;
123     }
124
125   }
126
127   private static final Logger LOG = LoggerFactory.getInstance().getLogger(AttributeUpdater.class);
128   private static final String MESSAGE_VERSION_EXTRACTION_REGEX = "\\/(v[0-9]+)";
129   private static final String ATTRIBUTES_UPDATED_SUCCESSFULLY = "Attributes updated successfully";
130   private static final String ATTRIBUTES_NOT_UPDATED = "Attributes not updated. ";
131
132   private ActiveInventoryAdapter aaiAdapter;
133   private UserValidator validator;
134   private OxmModelLoader oxmModelLoader;
135   private OxmEntityLookup oxmEntityLookup;
136   
137   /**
138    * Instantiates a new attribute updater.
139    * @throws AttributeUpdateException 
140    */
141   public AttributeUpdater(OxmModelLoader oxmModelLoader, OxmEntityLookup oxmEntityLookup, ActiveInventoryAdapter activeInventoryAdapter) throws AttributeUpdateException {
142     super();
143     this.oxmModelLoader = oxmModelLoader;
144     this.oxmEntityLookup = oxmEntityLookup;
145     this.aaiAdapter = activeInventoryAdapter;
146     
147     try {
148       this.validator = new UserValidator();
149     } catch (Exception exc) {
150       LOG.error(AaiUiMsgs.ATTRIBUTES_ERROR_GETTING_AAI_CONFIG_OR_ADAPTER, exc.getLocalizedMessage());
151       throw new AttributeUpdateException(exc);
152     }
153   }
154   
155   protected String getResourceBasePath() {
156
157     String versionStr = null;
158     if (oxmModelLoader != null) {
159       versionStr = String.valueOf(oxmModelLoader.getLatestVersionNum());
160     }
161
162     return "/aai/v" + versionStr;
163
164   }
165   
166   protected URI getBaseUri() {
167     return UriBuilder
168         .fromUri("https://" + aaiAdapter.getEndpointConfig().getEndpointIpAddress() + ":"
169             + aaiAdapter.getEndpointConfig().getEndpointServerPort() + getResourceBasePath())
170         .build();
171   }
172
173   /**
174    * Update object attribute.
175    *
176    * @param objectUri - Valid URI of the object as per OXM model.
177    * @param attributeValues - Map of (attribute-name & attribute-value) for
178    *        any attributes to be updated to the value.
179    * @param attUid - ATTUID of the user requesting the update.
180    * @return - OperationResult with success or failure reason.
181    */
182   public OperationResult updateObjectAttribute(String objectUri, Map<String, Object> attributeValues, String attUid) {
183     OperationResult result = new OperationResult();
184     LOG.info(AaiUiMsgs.ATTRIBUTES_UPDATE_METHOD_CALLED, objectUri, attUid, String.valueOf(attributeValues));
185     if (!validator.isAuthorizedUser(attUid)) {
186       result.setResultCode(403);
187       result.setResult(String.format("User %s is not authorized for Attributes update ", attUid));
188       LOG.error(AaiUiMsgs.ATTRIBUTES_USER_NOT_AUTHORIZED_TO_UPDATE, attUid);
189       return result;
190     }
191
192     AaiEditObject object = null;
193
194     try {
195       object = getEditObjectFromUri(objectUri);
196     } catch (AttributeUpdateException exc) {
197       result.setResultCode(400);
198       result.setResult(ATTRIBUTES_NOT_UPDATED);
199       LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_EXCEPTION, exc.getLocalizedMessage());
200       return result;
201     }
202     try {
203       String jsonPayload = convertEditRequestToJson(object, attributeValues);
204       String patchUri = getBaseUri().toString() + getRelativeUri(objectUri);
205
206       
207       /*
208        * FIX ME:   Dave Adams, 8-Nov-2017
209        */
210       
211       //result = aaiAdapter.doPatch(patchUri, jsonPayload, MediaType.APPLICATION_JSON);
212
213       result = new OperationResult();
214       result.setResultCode(404);
215       
216       if (result.getResultCode() == 200) {
217         result.setResult(ATTRIBUTES_UPDATED_SUCCESSFULLY);
218         String message = result.getResult() + " for " + objectUri;
219         LOG.info(AaiUiMsgs.INFO_GENERIC, message);
220       } else {
221         String message = ATTRIBUTES_NOT_UPDATED + " For: " + objectUri + ". AAI PATCH Status Code : "
222             + result.getResultCode() + ". Error : " + result.getResult();
223         LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_MESSAGE, message);
224       }
225     } catch (AttributeUpdateException exc) {
226       result.setResultCode(500);
227       result.setResult(ATTRIBUTES_NOT_UPDATED + exc.getLocalizedMessage());
228       LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_EXCEPTION, exc.getLocalizedMessage());
229     }
230     return result;
231
232   }
233
234   /**
235    * Gets the relative uri.
236    *
237    * @param objectUri the object uri
238    * @return the relative uri
239    */
240   public String getRelativeUri(String objectUri) {
241     String tempUri = objectUri;
242     final Pattern pattern = Pattern.compile(MESSAGE_VERSION_EXTRACTION_REGEX, Pattern.DOTALL);
243     Matcher matcher = pattern.matcher(objectUri);
244     while (matcher.find()) {
245       tempUri = objectUri.substring(matcher.end());
246     }
247     if (!tempUri.startsWith("/")) {
248       tempUri = "/" + tempUri;
249     }
250     return tempUri;
251   }
252
253   /**
254    * Gets the edits the object from uri.
255    *
256    * @param objectUri the object uri
257    * @return the edits the object from uri
258    * @throws AttributeUpdateException the attribute update exception
259    */
260   public AaiEditObject getEditObjectFromUri(String objectUri) throws AttributeUpdateException {
261
262     AaiEditObject object = new AaiEditObject();
263     String version = getVersionFromUri(objectUri);
264
265     if ( null == version ) {
266       version = "v" + String.valueOf(oxmModelLoader.getLatestVersionNum());
267     }
268     object.setSchemaVersion(version);
269
270     String[] values = objectUri.split("/");
271     if (values.length < 2) {
272       throw new AttributeUpdateException("Invalid or malformed object URI : " + objectUri);
273     }
274     String keyValue = values[values.length - 1];
275     String rootElement = values[values.length - 2];
276
277     object.setKeyValue(keyValue);
278     object.setRootElement(rootElement);
279
280     String objectJavaType = null;
281     Map<String, DynamicType> entityTypeLookup = oxmEntityLookup.getEntityTypeLookup();
282     DynamicType entity = entityTypeLookup.get(rootElement);
283     if ( null != entity ) {
284       objectJavaType = entity.getName();
285       String message = "Descriptor: Alias: " + objectJavaType + " : DefaultRootElement: "
286           + rootElement;
287       LOG.debug(AaiUiMsgs.DEBUG_GENERIC, message);
288     }
289     
290     
291     if (objectJavaType == null) {
292       throw new AttributeUpdateException(
293           "Object type could not be determined from the URI : " + objectUri);
294     }
295     object.setObjectType(objectJavaType);
296
297     // Set key attribute name
298     final List<String> primaryKeys = entity.getDescriptor().getPrimaryKeyFieldNames();
299
300     if (primaryKeys.isEmpty()) {
301       throw new AttributeUpdateException("Object primary key not found in OXM version " + version);
302     }
303
304     for (int i = 0; i < primaryKeys.size(); i++) {
305       final String primaryKey = primaryKeys.get(i);
306       if (primaryKey.indexOf("/text()") != -1) {
307         primaryKeys.set(i, primaryKey.replace("/text()", ""));
308       }
309     }
310     object.setKeyName(primaryKeys.iterator().next());
311
312     return object;
313   }
314
315   /**
316    * Gets the version from uri.
317    *
318    * @param objectUri the object uri
319    * @return the version from uri
320    * @throws AttributeUpdateException the attribute update exception
321    */
322   private String getVersionFromUri(String objectUri) throws AttributeUpdateException {
323     final Pattern pattern = Pattern.compile(MESSAGE_VERSION_EXTRACTION_REGEX, Pattern.DOTALL);
324     Matcher matcher = pattern.matcher(objectUri);
325     String messageSchemaVersion = null;
326     while (matcher.find()) {
327       messageSchemaVersion = matcher.group(1);
328       break;
329     }
330     return messageSchemaVersion;
331   }
332
333   /**
334    * Convert edit request to json.
335    *
336    * @param object the object
337    * @param attributeValues the attribute values
338    * @return the string
339    * @throws AttributeUpdateException the attribute update exception
340    */
341   private static String convertEditRequestToJson(AaiEditObject object,
342       Map<String, Object> attributeValues) throws AttributeUpdateException {
343
344     ObjectMapper mapper = new ObjectMapper();
345     mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.KebabCaseStrategy());
346     ObjectWriter ow = mapper.writer();
347
348     Map<String, Object> patchAttributes = new HashMap<>();
349     patchAttributes.put(object.getKeyName(), object.getKeyValue());
350     patchAttributes.putAll(attributeValues);
351
352     try {
353       return ow.writeValueAsString(patchAttributes);
354     } catch (JsonProcessingException exc) {
355       throw new AttributeUpdateException("Caught a JPE while creating PATCH request body = ", exc);
356     }
357   }
358 }