update sparky with configurable features
[aai/sparky-be.git] / sparkybe-onap-service / 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   private String domain;
137   
138   /**
139    * Instantiates a new attribute updater.
140    * @throws AttributeUpdateException 
141    */
142   public AttributeUpdater(OxmModelLoader oxmModelLoader, OxmEntityLookup oxmEntityLookup, ActiveInventoryAdapter activeInventoryAdapter,String domain) throws AttributeUpdateException {
143     super();
144     this.oxmModelLoader = oxmModelLoader;
145     this.oxmEntityLookup = oxmEntityLookup;
146     this.aaiAdapter = activeInventoryAdapter;
147     this.domain = domain;
148     
149     try {
150       this.validator = new UserValidator();
151     } catch (Exception exc) {
152       LOG.error(AaiUiMsgs.ATTRIBUTES_ERROR_GETTING_AAI_CONFIG_OR_ADAPTER, exc.getLocalizedMessage());
153       throw new AttributeUpdateException(exc);
154     }
155   }
156   
157   protected String getResourceBasePath() {
158
159     String versionStr = null;
160     if (oxmModelLoader != null) {
161       versionStr = String.valueOf(oxmModelLoader.getOxmApiVersion());
162     }
163
164     return "/" + domain + "/v" + versionStr;
165
166   }
167   
168   protected URI getBaseUri() {
169     return UriBuilder
170         .fromUri("https://" + aaiAdapter.getEndpointConfig().getEndpointIpAddress() + ":"
171             + aaiAdapter.getEndpointConfig().getEndpointServerPort() + getResourceBasePath())
172         .build();
173   }
174
175   /**
176    * Update object attribute.
177    *
178    * @param objectUri - Valid URI of the object as per OXM model.
179    * @param attributeValues - Map of (attribute-name & attribute-value) for
180    *        any attributes to be updated to the value.
181    * @param attUid - ATTUID of the user requesting the update.
182    * @return - OperationResult with success or failure reason.
183    */
184   public OperationResult updateObjectAttribute(String objectUri, Map<String, Object> attributeValues, String attUid) {
185     OperationResult result = new OperationResult();
186     LOG.info(AaiUiMsgs.ATTRIBUTES_UPDATE_METHOD_CALLED, objectUri, attUid, String.valueOf(attributeValues));
187     if (!validator.isAuthorizedUser(attUid)) {
188       result.setResultCode(403);
189       result.setResult(String.format("User %s is not authorized for Attributes update ", attUid));
190       LOG.error(AaiUiMsgs.ATTRIBUTES_USER_NOT_AUTHORIZED_TO_UPDATE, attUid);
191       return result;
192     }
193
194     AaiEditObject object = null;
195
196     try {
197       object = getEditObjectFromUri(objectUri);
198     } catch (AttributeUpdateException exc) {
199       result.setResultCode(400);
200       result.setResult(ATTRIBUTES_NOT_UPDATED);
201       LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_EXCEPTION, exc.getLocalizedMessage());
202       return result;
203     }
204     try {
205       String jsonPayload = convertEditRequestToJson(object, attributeValues);
206       String patchUri = getBaseUri().toString() + getRelativeUri(objectUri);
207
208       
209       /*
210        * FIX ME:   Dave Adams, 8-Nov-2017
211        */
212       
213       //result = aaiAdapter.doPatch(patchUri, jsonPayload, MediaType.APPLICATION_JSON);
214
215       result = new OperationResult();
216       result.setResultCode(404);
217       
218       if (result.getResultCode() == 200) {
219         result.setResult(ATTRIBUTES_UPDATED_SUCCESSFULLY);
220         String message = result.getResult() + " for " + objectUri;
221         LOG.info(AaiUiMsgs.INFO_GENERIC, message);
222       } else {
223         String message = ATTRIBUTES_NOT_UPDATED + " For: " + objectUri + ". AAI PATCH Status Code : "
224             + result.getResultCode() + ". Error : " + result.getResult();
225         LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_MESSAGE, message);
226       }
227     } catch (AttributeUpdateException exc) {
228       result.setResultCode(500);
229       result.setResult(ATTRIBUTES_NOT_UPDATED + exc.getLocalizedMessage());
230       LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_EXCEPTION, exc.getLocalizedMessage());
231     }
232     return result;
233
234   }
235
236   /**
237    * Gets the relative uri.
238    *
239    * @param objectUri the object uri
240    * @return the relative uri
241    */
242   public String getRelativeUri(String objectUri) {
243     String tempUri = objectUri;
244     final Pattern pattern = Pattern.compile(MESSAGE_VERSION_EXTRACTION_REGEX, Pattern.DOTALL);
245     Matcher matcher = pattern.matcher(objectUri);
246     while (matcher.find()) {
247       tempUri = objectUri.substring(matcher.end());
248     }
249     if (!tempUri.startsWith("/")) {
250       tempUri = "/" + tempUri;
251     }
252     return tempUri;
253   }
254
255   /**
256    * Gets the edits the object from uri.
257    *
258    * @param objectUri the object uri
259    * @return the edits the object from uri
260    * @throws AttributeUpdateException the attribute update exception
261    */
262   public AaiEditObject getEditObjectFromUri(String objectUri) throws AttributeUpdateException {
263
264     AaiEditObject object = new AaiEditObject();
265     String version = getVersionFromUri(objectUri);
266
267     if ( null == version ) {
268       version = "v" + String.valueOf(oxmModelLoader.getOxmApiVersion());
269     }
270     object.setSchemaVersion(version);
271
272     String[] values = objectUri.split("/");
273     if (values.length < 2) {
274       throw new AttributeUpdateException("Invalid or malformed object URI : " + objectUri);
275     }
276     String keyValue = values[values.length - 1];
277     String rootElement = values[values.length - 2];
278
279     object.setKeyValue(keyValue);
280     object.setRootElement(rootElement);
281
282     String objectJavaType = null;
283     Map<String, DynamicType> entityTypeLookup = oxmEntityLookup.getEntityTypeLookup();
284     DynamicType entity = entityTypeLookup.get(rootElement);
285     if ( null != entity ) {
286       objectJavaType = entity.getName();
287       String message = "Descriptor: Alias: " + objectJavaType + " : DefaultRootElement: "
288           + rootElement;
289       LOG.debug(AaiUiMsgs.DEBUG_GENERIC, message);
290     }
291     
292     
293     if (objectJavaType == null) {
294       throw new AttributeUpdateException(
295           "Object type could not be determined from the URI : " + objectUri);
296     }
297     object.setObjectType(objectJavaType);
298
299     // Set key attribute name
300     final List<String> primaryKeys = entity.getDescriptor().getPrimaryKeyFieldNames();
301
302     if (primaryKeys.isEmpty()) {
303       throw new AttributeUpdateException("Object primary key not found in OXM version " + version);
304     }
305
306     for (int i = 0; i < primaryKeys.size(); i++) {
307       final String primaryKey = primaryKeys.get(i);
308       if (primaryKey.indexOf("/text()") != -1) {
309         primaryKeys.set(i, primaryKey.replace("/text()", ""));
310       }
311     }
312     object.setKeyName(primaryKeys.iterator().next());
313
314     return object;
315   }
316
317   /**
318    * Gets the version from uri.
319    *
320    * @param objectUri the object uri
321    * @return the version from uri
322    * @throws AttributeUpdateException the attribute update exception
323    */
324   private String getVersionFromUri(String objectUri) throws AttributeUpdateException {
325     final Pattern pattern = Pattern.compile(MESSAGE_VERSION_EXTRACTION_REGEX, Pattern.DOTALL);
326     Matcher matcher = pattern.matcher(objectUri);
327     String messageSchemaVersion = null;
328     while (matcher.find()) {
329       messageSchemaVersion = matcher.group(1);
330       break;
331     }
332     return messageSchemaVersion;
333   }
334
335   /**
336    * Convert edit request to json.
337    *
338    * @param object the object
339    * @param attributeValues the attribute values
340    * @return the string
341    * @throws AttributeUpdateException the attribute update exception
342    */
343   private static String convertEditRequestToJson(AaiEditObject object,
344       Map<String, Object> attributeValues) throws AttributeUpdateException {
345
346     ObjectMapper mapper = new ObjectMapper();
347     mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.KebabCaseStrategy());
348     ObjectWriter ow = mapper.writer();
349
350     Map<String, Object> patchAttributes = new HashMap<>();
351     patchAttributes.put(object.getKeyName(), object.getKeyValue());
352     patchAttributes.putAll(attributeValues);
353
354     try {
355       return ow.writeValueAsString(patchAttributes);
356     } catch (JsonProcessingException exc) {
357       throw new AttributeUpdateException("Caught a JPE while creating PATCH request body = ", exc);
358     }
359   }
360 }