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