f992da7f45ff69fd37ba5407ae8573c32231b677
[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.editattributes.exception.AttributeUpdateException;
42 import org.onap.aai.sparky.logging.AaiUiMsgs;
43
44 import com.fasterxml.jackson.core.JsonProcessingException;
45 import com.fasterxml.jackson.databind.ObjectMapper;
46 import com.fasterxml.jackson.databind.ObjectWriter;
47 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
48
49 /**
50  * Class to process attribute updates on AAI objects.
51  *
52  *
53  */
54 public class AttributeUpdater {
55   
56   /**
57    * The Class AaiEditObject.
58    */
59   public class AaiEditObject {
60     String objectType;
61     String rootElement;
62     String keyName;
63     String keyValue;
64     String schemaVersion;
65
66     /**
67      * Instantiates a new aai edit object.
68      */
69     public AaiEditObject() {
70
71     }
72
73     /**
74      * Instantiates a new aai edit object.
75      *
76      * @param objectType the object type
77      * @param idName the id name
78      * @param schemaVersion the schema version
79      */
80     public AaiEditObject(String objectType, String idName, String schemaVersion) {
81       super();
82       this.objectType = objectType;
83       this.keyName = idName;
84       this.schemaVersion = schemaVersion;
85     }
86
87     public String getObjectType() {
88       return objectType;
89     }
90
91     public void setObjectType(String objectType) {
92       this.objectType = objectType;
93     }
94
95     public String getKeyName() {
96       return keyName;
97     }
98
99     public void setKeyName(String idName) {
100       this.keyName = idName;
101     }
102
103     public String getSchemaVersion() {
104       return schemaVersion;
105     }
106
107     public void setSchemaVersion(String schemaVersion) {
108       this.schemaVersion = schemaVersion;
109     }
110
111     public void setKeyValue(String keyValue) {
112       this.keyValue = keyValue;
113     }
114
115     public String getKeyValue() {
116       return keyValue;
117     }
118
119     public String getRootElement() {
120       return rootElement;
121     }
122
123     public void setRootElement(String rootElement) {
124       this.rootElement = rootElement;
125     }
126
127   }
128
129   private static final Logger LOG = LoggerFactory.getInstance().getLogger(AttributeUpdater.class);
130   private static final String MESSAGE_VERSION_EXTRACTION_REGEX = "\\/(v[0-9]+)";
131   private static final String ATTRIBUTES_UPDATED_SUCCESSFULLY = "Attributes updated successfully";
132   private static final String ATTRIBUTES_NOT_UPDATED = "Attributes not updated. ";
133
134   private ActiveInventoryAdapter aaiAdapter;
135   private UserValidator validator;
136   private OxmModelLoader oxmModelLoader;
137   private OxmEntityLookup oxmEntityLookup;
138   
139   /**
140    * Instantiates a new attribute updater.
141    * @throws AttributeUpdateException 
142    */
143   public AttributeUpdater(OxmModelLoader oxmModelLoader, OxmEntityLookup oxmEntityLookup, ActiveInventoryAdapter activeInventoryAdapter) throws AttributeUpdateException {
144     super();
145     this.oxmModelLoader = oxmModelLoader;
146     this.oxmEntityLookup = oxmEntityLookup;
147     this.aaiAdapter = activeInventoryAdapter;
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.getLatestVersionNum());
162     }
163
164     return "/aai/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.getLatestVersionNum());
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 }