Favor interfaces
[ccsdk/sli/core.git] / sli / provider / src / main / java / org / onap / ccsdk / sli / core / sli / provider / MdsalHelper.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : CCSDK
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
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
22 package org.onap.ccsdk.sli.core.sli.provider;
23
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.PrintStream;
29 import java.lang.reflect.Constructor;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Modifier;
32 import java.lang.reflect.ParameterizedType;
33 import java.lang.reflect.Type;
34 import java.util.LinkedList;
35 import java.util.List;
36 import java.util.Properties;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddressBuilder;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefixBuilder;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
45 import org.opendaylight.yangtools.yang.binding.Identifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public class MdsalHelper {
50
51     private static final Logger LOG = LoggerFactory.getLogger(MdsalHelper.class);
52     private static Properties yangMappingProperties = new Properties();
53
54     @Deprecated
55     public static void setProperties(Properties input) {
56         setYangMappingProperties(input);
57     }
58
59     public static void setYangMappingProperties(Properties properties) {
60         for (Object propNameObj : properties.keySet()) {
61             String propName = (String) propNameObj;
62             MdsalHelper.yangMappingProperties.setProperty(propName, properties.getProperty(propName));
63         }
64     }
65
66     public static void loadProperties(String propertiesFile) {
67         File file = new File(propertiesFile);
68         Properties properties = new Properties();
69         if (file.isFile() && file.canRead()) {
70             try (InputStream input = new FileInputStream(file)) {
71                 properties.load(input);
72                 MdsalHelper.setYangMappingProperties(properties);
73                 LOG.info("Loaded properties from " + propertiesFile);
74             } catch (Exception e) {
75                 LOG.error("Failed to load properties " + propertiesFile + "\n", e);
76             }
77         } else {
78             LOG.error("Failed to load the properties file " + propertiesFile + "\n");
79             LOG.error("Either isFile or canRead returned false for " + propertiesFile + "\n");
80         }
81     }
82
83     public static Properties toProperties(Properties props, Object fromObj) {
84         Class fromClass = null;
85
86         if (fromObj != null) {
87             fromClass = fromObj.getClass();
88         }
89         return toProperties(props, "", fromObj, fromClass);
90     }
91
92     public static Properties toProperties(Properties props, String pfx, Object fromObj) {
93         Class fromClass = null;
94
95         if (fromObj != null) {
96             fromClass = fromObj.getClass();
97         }
98
99         return toProperties(props, pfx, fromObj, fromClass);
100     }
101
102     public static Properties toProperties(Properties props, String pfx, Object fromObj, Class fromClass) {
103
104         if (fromObj == null) {
105             return props;
106         }
107
108         LOG.trace("Extracting properties from " + fromClass.getName() + " class");
109         if (fromObj instanceof List) {
110
111             // Class is a List. List should contain yang-generated classes.
112             LOG.trace(fromClass.getName() + " is a List");
113
114             List fromList = (List) fromObj;
115
116             for (int i = 0; i < fromList.size(); i++) {
117                 toProperties(props, pfx + "[" + i + "]", fromList.get(i), fromClass);
118             }
119             props.setProperty(pfx + "_length", Integer.toString(fromList.size()));
120
121         } else if (isYangGenerated(fromClass)) {
122             // Class is yang generated.
123             LOG.trace(fromClass.getName() + " is a Yang-generated class");
124
125             String propNamePfx = null;
126
127             // If called from a list (so prefix ends in ']'), don't
128             // add class name again
129             if (pfx.endsWith("]")) {
130                 propNamePfx = pfx;
131             } else {
132                 if ((pfx != null) && (pfx.length() > 0)) {
133                     propNamePfx = pfx;
134                 } else {
135                     propNamePfx = toLowerHyphen(fromClass.getSimpleName());
136                 }
137
138                 if (propNamePfx.endsWith("-builder")) {
139                     propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-builder".length());
140                 }
141
142                 if (propNamePfx.endsWith("-impl")) {
143                     propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-impl".length());
144                 }
145             }
146
147             // Iterate through getter methods to figure out values we need to
148             // save from
149
150             int numGetters = 0;
151             String lastGetterName = null;
152             String propVal = null;
153
154             for (Method m : fromClass.getMethods()) {
155                 if (isGetter(m)) {
156
157                     numGetters++;
158                     lastGetterName = m.getName();
159
160                     Class returnType = m.getReturnType();
161                     String fieldName;
162                     if (m.getName().startsWith("get")) {
163                         fieldName = toLowerHyphen(m.getName().substring(3));
164                     } else {
165
166                         fieldName = toLowerHyphen(m.getName().substring(2));
167                     }
168
169                     fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
170
171                     // Is the return type a yang generated class?
172                     if (isYangGenerated(returnType)) {
173                         // Is it an enum?
174                         if (returnType.isEnum()) {
175                             // Return type is a typedef. Save its value.
176                             try {
177                                 boolean isAccessible = m.isAccessible();
178                                 if (!isAccessible) {
179                                     m.setAccessible(true);
180                                 }
181
182                                 Object retValue = m.invoke(fromObj);
183
184                                 if (!isAccessible) {
185                                     m.setAccessible(isAccessible);
186                                 }
187                                 if (retValue != null) {
188                                     String propName = propNamePfx + "." + fieldName;
189                                     propVal = retValue.toString();
190                                     props.setProperty(propName, mapEnumeratedValue(fieldName, propVal));
191                                 }
192                             } catch (Exception e) {
193                                 LOG.error(
194                                         "Caught exception trying to convert Yang-generated enum returned by "
195                                                 + fromClass.getName() + "." + m.getName() + "() to Properties entry",
196                                         e);
197                             }
198                         } else if (isIpv4Address(returnType)) {
199                             // Save its value
200                             try {
201                                 String propName = propNamePfx + "." + fieldName;
202                                 boolean isAccessible = m.isAccessible();
203                                 if (!isAccessible) {
204                                     m.setAccessible(true);
205                                 }
206                                 Ipv4Address retValue = (Ipv4Address) m.invoke(fromObj);
207                                 if (!isAccessible) {
208                                     m.setAccessible(isAccessible);
209                                 }
210
211                                 if (retValue != null) {
212                                     propVal = retValue.getValue().toString();
213                                     LOG.debug("Setting property " + propName + " to " + propVal);
214                                     props.setProperty(propName, propVal);
215
216                                 }
217                             } catch (Exception e) {
218                                 LOG.error("Caught exception trying to convert value returned by " + fromClass.getName()
219                                         + "." + m.getName() + "() to Properties entry", e);
220                             }
221                         } else if (isIpv6Address(returnType)) {
222                             // Save its value
223                             try {
224                                 String propName = propNamePfx + "." + fieldName;
225                                 boolean isAccessible = m.isAccessible();
226                                 if (!isAccessible) {
227                                     m.setAccessible(true);
228                                 }
229                                 Ipv6Address retValue = (Ipv6Address) m.invoke(fromObj);
230                                 if (!isAccessible) {
231                                     m.setAccessible(isAccessible);
232                                 }
233
234                                 if (retValue != null) {
235                                     propVal = retValue.getValue().toString();
236                                     LOG.debug("Setting property " + propName + " to " + propVal);
237                                     props.setProperty(propName, propVal);
238
239                                 }
240                             } catch (Exception e) {
241                                 LOG.error("Caught exception trying to convert value returned by " + fromClass.getName()
242                                         + "." + m.getName() + "() to Properties entry", e);
243                             }
244                         } else if (isIpAddress(returnType)) {
245                             // Save its value
246                             try {
247                                 String propName = propNamePfx + "." + fieldName;
248                                 boolean isAccessible = m.isAccessible();
249                                 if (!isAccessible) {
250                                     m.setAccessible(true);
251                                 }
252                                 IpAddress retValue = (IpAddress) m.invoke(fromObj);
253                                 if (!isAccessible) {
254                                     m.setAccessible(isAccessible);
255                                 }
256
257                                 if (retValue != null) {
258                                     propVal = new String(retValue.getValue());
259                                     LOG.debug("Setting property " + propName + " to " + propVal);
260                                     props.setProperty(propName, propVal);
261
262                                 }
263                             } catch (Exception e) {
264                                 LOG.error("Caught exception trying to convert value returned by " + fromClass.getName()
265                                         + "." + m.getName() + "() to Properties entry", e);
266                             }
267                         } else if (isIpPrefix(returnType)) {
268                             // Save its value
269                             try {
270                                 String propName = propNamePfx + "." + fieldName;
271                                 boolean isAccessible = m.isAccessible();
272                                 if (!isAccessible) {
273                                     m.setAccessible(true);
274                                 }
275                                 IpPrefix retValue = (IpPrefix) m.invoke(fromObj);
276                                 if (!isAccessible) {
277                                     m.setAccessible(isAccessible);
278                                 }
279
280                                 if (retValue != null) {
281                                     propVal = new String(retValue.getValue());
282                                     LOG.debug("Setting property " + propName + " to " + propVal);
283                                     props.setProperty(propName, propVal);
284
285                                 }
286                             } catch (Exception e) {
287                                 LOG.error("Caught exception trying to convert value returned by " + fromClass.getName()
288                                         + "." + m.getName() + "() to Properties entry", e);
289                             }
290                         } else if (isPortNumber(returnType)) {
291                             // Save its value
292                             try {
293                                 String propName = propNamePfx + "." + fieldName;
294                                 boolean isAccessible = m.isAccessible();
295                                 if (!isAccessible) {
296                                     m.setAccessible(true);
297                                 }
298                                 PortNumber retValue = (PortNumber) m.invoke(fromObj);
299                                 if (!isAccessible) {
300                                     m.setAccessible(isAccessible);
301                                 }
302
303                                 if (retValue != null) {
304                                     propVal = "" + retValue.getValue();
305                                     LOG.debug("Setting property " + propName + " to " + propVal);
306                                     props.setProperty(propName, propVal);
307
308                                 }
309                             } catch (Exception e) {
310                                 LOG.error("Caught exception trying to convert value returned by " + fromClass.getName()
311                                         + "." + m.getName() + "() to Properties entry", e);
312                             }
313                         } else if (isDscp(returnType)) {
314                             // Save its value
315                             try {
316                                 String propName = propNamePfx + "." + fieldName;
317                                 boolean isAccessible = m.isAccessible();
318                                 if (!isAccessible) {
319                                     m.setAccessible(true);
320                                 }
321                                 Dscp retValue = (Dscp) m.invoke(fromObj);
322                                 if (!isAccessible) {
323                                     m.setAccessible(isAccessible);
324                                 }
325
326                                 if (retValue != null) {
327                                     propVal = "" + retValue.getValue();
328                                     LOG.debug("Setting property " + propName + " to " + propVal);
329                                     props.setProperty(propName, propVal);
330
331                                 }
332                             } catch (Exception e) {
333                                 LOG.error("Caught exception trying to convert value returned by " + fromClass.getName()
334                                         + "." + m.getName() + "() to Properties entry", e);
335                             }
336                         } else {
337                             try {
338                                 boolean isAccessible = m.isAccessible();
339                                 if (!isAccessible) {
340                                     m.setAccessible(true);
341                                 }
342                                 Object retValue = m.invoke(fromObj);
343
344                                 if (retValue instanceof byte[]) {
345                                     LOG.trace(m.getName() + " returns a byte[]");
346                                     retValue = new String((byte[]) retValue, "UTF-8");
347                                     LOG.trace("Converted byte array " + propNamePfx + "." + fieldName + "to string "
348                                             + retValue);
349                                 }
350                                 if (!isAccessible) {
351                                     m.setAccessible(isAccessible);
352                                 }
353                                 if (retValue != null) {
354                                     toProperties(props, propNamePfx + "." + fieldName, retValue, returnType);
355                                 }
356                             } catch (Exception e) {
357
358                                 if (m.getName().equals("getKey")) {
359                                     LOG.trace("Caught " + e.getClass().getName()
360                                             + " exception trying to convert results from getKey() - ignoring");
361                                 } else {
362                                     LOG.error("Caught exception trying to convert Yang-generated class returned by"
363                                             + fromClass.getName() + "." + m.getName() + "() to Properties entry", e);
364                                 }
365                             }
366                         }
367                     } else if (returnType.equals(Class.class)) {
368
369                         LOG.trace(m.getName() + " returns a Class object - not interested");
370
371                     } else if (List.class.isAssignableFrom(returnType)) {
372
373                         // This getter method returns a list.
374                         try {
375                             boolean isAccessible = m.isAccessible();
376                             if (!isAccessible) {
377                                 m.setAccessible(true);
378                             }
379                             Object retList = m.invoke(fromObj);
380                             if (!isAccessible) {
381                                 m.setAccessible(isAccessible);
382                             }
383                             // Figure out what type of elements are stored in
384                             // this array.
385                             Type paramType = m.getGenericReturnType();
386                             Type elementType = ((ParameterizedType) paramType).getActualTypeArguments()[0];
387                             toProperties(props, propNamePfx + "." + fieldName, retList, (Class) elementType);
388                         } catch (Exception e) {
389                             LOG.error("Caught exception trying to convert List returned by " + fromClass.getName() + "."
390                                     + m.getName() + "() to Properties entry", e);
391                         }
392
393                     } else {
394
395                         // Method returns something that is not a List and not
396                         // yang-generated.
397                         // Save its value
398                         try {
399                             String propName = propNamePfx + "." + fieldName;
400                             boolean isAccessible = m.isAccessible();
401                             if (!isAccessible) {
402                                 m.setAccessible(true);
403                             }
404                             Object propValObj = m.invoke(fromObj);
405                             if (!isAccessible) {
406                                 m.setAccessible(isAccessible);
407                             }
408
409                             if (propValObj != null) {
410                                 if (propValObj instanceof byte[]) {
411                                     LOG.trace(m.getName() + " returns a byte[]");
412                                     propVal = new String((byte[]) propValObj, "UTF-8");
413                                     LOG.trace("Converted byte array " + propNamePfx + "." + fieldName + "to string "
414                                             + propVal);
415
416                                 } else {
417                                     propVal = propValObj.toString();
418                                 }
419                                 LOG.debug("Setting property " + propName + " to " + propVal);
420                                 props.setProperty(propName, propVal);
421
422                             }
423                         } catch (Exception e) {
424                             if (m.getName().equals("getKey")) {
425                                 LOG.trace("Caught " + e.getClass().getName()
426                                         + " exception trying to convert results from getKey() - ignoring");
427                             } else {
428                                 LOG.error("Caught exception trying to convert value returned by" + fromClass.getName()
429                                         + "." + m.getName() + "() to Properties entry", e);
430                             }
431                         }
432                     }
433
434                 }
435             }
436
437             // End of method loop. If there was only one getter, named
438             // "getValue", then
439             // set value identified by "prefix" to that one value.
440             if ((numGetters == 1) && ("getValue".equals(lastGetterName))) {
441                 LOG.trace("getValueFIX : " + propNamePfx + " only has getValue() getter - setting " + propNamePfx
442                         + " = " + propVal);
443                 props.setProperty(propNamePfx, propVal);
444             } else {
445                 LOG.trace("getValueFIX : " + propNamePfx + " has " + numGetters + " getter(s), last one found was "
446                         + lastGetterName);
447
448             }
449
450         } else {
451             // Class is not yang generated and not a list
452             // It must be an element of a leaf list - set "prefix" to value
453             String fromVal = null;
454             if (fromObj instanceof byte[]) {
455                 try {
456                     fromVal = new String((byte[]) fromObj, "UTF-8");
457                     LOG.trace("Converted byte array " + pfx + "to string " + fromVal);
458                 } catch (Exception e) {
459                     LOG.warn("Caught exception trying to convert " + pfx + " from byte[] to String", e);
460                     fromVal = fromObj.toString();
461                 }
462
463             } else {
464                 fromVal = fromObj.toString();
465             }
466             LOG.debug("Setting property " + pfx + " to " + fromVal);
467             props.setProperty(pfx, fromVal);
468         }
469
470         return (props);
471     }
472
473     public static Object toBuilder(Properties props, Object toObj) {
474
475         return (toBuilder(props, "", toObj));
476     }
477
478     public static List toList(Properties props, String pfx, List toObj, Class elemType) {
479
480         int maxIdx = -1;
481         boolean foundValue = false;
482
483         LOG.trace("Saving properties to List<" + elemType.getName() + ">  from " + pfx);
484
485         if (props.contains(pfx + "_length")) {
486             try {
487                 int listLength = Integer.parseInt(props.getProperty(pfx + "_length"));
488
489                 if (listLength > 0) {
490                     maxIdx = listLength - 1;
491                 }
492             } catch (NumberFormatException e) {
493                 LOG.info("Invalid input for length ", e);
494             }
495         }
496
497         if (maxIdx == -1) {
498             // Figure out array size
499             for (Object pNameObj : props.keySet()) {
500                 String key = (String) pNameObj;
501
502                 if (key.startsWith(pfx + "[")) {
503                     String idxStr = key.substring(pfx.length() + 1);
504                     int endloc = idxStr.indexOf("]");
505                     if (endloc != -1) {
506                         idxStr = idxStr.substring(0, endloc);
507                     }
508
509                     try {
510                         int curIdx = Integer.parseInt(idxStr);
511                         if (curIdx > maxIdx) {
512                             maxIdx = curIdx;
513                         }
514                     } catch (Exception e) {
515                         LOG.error("Illegal subscript in property {}", key, e);
516                     }
517
518                 }
519             }
520         }
521
522         LOG.trace(pfx + " has max index of " + maxIdx);
523         for (int i = 0; i <= maxIdx; i++) {
524
525             String curBase = pfx + "[" + i + "]";
526
527             if (isYangGenerated(elemType)) {
528                 String builderName = elemType.getName() + "Builder";
529                 try {
530                     Class builderClass = Class.forName(builderName);
531                     Object builderObj = builderClass.newInstance();
532                     Method buildMethod = builderClass.getMethod("build");
533                     builderObj = toBuilder(props, curBase, builderObj, true);
534                     if (builderObj != null) {
535                         LOG.trace("Calling " + builderObj.getClass().getName() + "." + buildMethod.getName() + "()");
536                         Object builtObj = buildMethod.invoke(builderObj);
537                         toObj.add(builtObj);
538                         foundValue = true;
539                     }
540
541                 } catch (ClassNotFoundException e) {
542                     LOG.warn("Could not find builder class {}", builderName, e);
543                 } catch (Exception e) {
544                     LOG.error("Caught exception trying to populate list from {}", pfx, e);
545                 }
546             } else {
547                 // Must be a leaf list
548                 String curValue = props.getProperty(curBase, "");
549
550                 toObj.add(curValue);
551
552                 if ((curValue != null) && (curValue.length() > 0)) {
553                     foundValue = true;
554                 }
555             }
556
557         }
558
559         if (foundValue) {
560             return (toObj);
561         } else {
562             return (null);
563         }
564
565     }
566
567     public static Object toBuilder(Properties props, String pfx, Object toObj) {
568         return (toBuilder(props, pfx, toObj, false));
569     }
570
571     public static Object toBuilder(Properties props, String pfx, Object toObj, boolean preservePfx) {
572         Class toClass = toObj.getClass();
573         boolean foundValue = false;
574
575         LOG.trace("Saving properties to " + toClass.getName() + " class from " + pfx);
576
577         Ipv4Address addr;
578
579         if (isYangGenerated(toClass)) {
580             // Class is yang generated.
581             LOG.trace(toClass.getName() + " is a Yang-generated class");
582
583             String propNamePfx = null;
584             if (preservePfx) {
585                 propNamePfx = pfx;
586             } else {
587
588                 if ((pfx != null) && (pfx.length() > 0)) {
589                     propNamePfx = pfx + "." + toLowerHyphen(toClass.getSimpleName());
590                 } else {
591                     propNamePfx = toLowerHyphen(toClass.getSimpleName());
592                 }
593
594                 if (propNamePfx.endsWith("-builder")) {
595                     propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-builder".length());
596                 }
597
598                 if (propNamePfx.endsWith("-impl")) {
599                     propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-impl".length());
600                 }
601             }
602
603             if (toObj instanceof Identifier) {
604                 LOG.trace(toClass.getName() + " is a Key - skipping");
605                 return (toObj);
606             }
607
608             // Iterate through getter methods to figure out values we need to
609             // set
610
611             for (Method m : toClass.getMethods()) {
612                 if (isSetter(m)) {
613                     Class paramTypes[] = m.getParameterTypes();
614                     Class paramClass = paramTypes[0];
615
616                     String fieldName = toLowerHyphen(m.getName().substring(3));
617                     fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
618
619                     String propName = propNamePfx + "." + fieldName;
620
621                     String paramValue = props.getProperty(propName);
622                     if (paramValue == null) {
623                         LOG.trace(propName + " is unset");
624                     } else if ("".equals(paramValue)) {
625                         LOG.trace(propName + " was set to the empty string, setting it to null");
626                         paramValue = null;
627                     } else {
628                         LOG.trace(propName + " = " + paramValue);
629                     }
630
631                     // Is the return type a yang generated class?
632                     if (isYangGenerated(paramClass)) {
633                         // Is it an enum?
634                         if (paramClass.isEnum()) {
635
636                             LOG.trace(m.getName() + " expects an Enum");
637                             // Param type is a typedef.
638                             if ((paramValue != null) && (paramValue.length() > 0)) {
639                                 Object paramObj = null;
640
641                                 try {
642                                     paramObj = Enum.valueOf(paramClass, toJavaEnum(paramValue));
643                                 } catch (Exception e) {
644                                     LOG.error("Caught exception trying to convert field " + propName + " to enum "
645                                             + paramClass.getName(), e);
646                                 }
647
648                                 try {
649                                     boolean isAccessible = m.isAccessible();
650                                     if (!isAccessible) {
651                                         m.setAccessible(true);
652                                     }
653
654                                     LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "("
655                                             + paramValue + ")");
656                                     m.invoke(toObj, paramObj);
657
658                                     if (!isAccessible) {
659                                         m.setAccessible(isAccessible);
660                                     }
661                                     foundValue = true;
662
663                                 } catch (Exception e) {
664                                     LOG.error("Caught exception trying to create Yang-generated enum expected by"
665                                             + toClass.getName() + "." + m.getName() + "() from Properties entry", e);
666                                 }
667                             }
668                         } else {
669
670                             String simpleName = paramClass.getSimpleName();
671
672                             if ("Ipv4Address".equals(simpleName) || "Ipv6Address".equals(simpleName)
673                                     || "IpAddress".equals(simpleName)) {
674
675                                 if ((paramValue != null) && (paramValue.length() > 0)) {
676                                     try {
677                                         IpAddress ipAddr = IpAddressBuilder.getDefaultInstance(paramValue);
678
679                                         if ("Ipv4Address".equals(simpleName)) {
680                                             m.invoke(toObj, ipAddr.getIpv4Address());
681                                         } else if ("Ipv6Address".equals(simpleName)) {
682                                             m.invoke(toObj, ipAddr.getIpv6Address());
683
684                                         } else {
685                                             m.invoke(toObj, ipAddr);
686                                         }
687                                         foundValue = true;
688                                     } catch (Exception e) {
689                                         LOG.error("Caught exception calling " + toClass.getName() + "." + m.getName()
690                                                 + "(" + paramValue + ")", e);
691
692                                     }
693                                 } else {
694                                     try {
695                                         boolean isAccessible = m.isAccessible();
696                                         if (!isAccessible) {
697                                             m.setAccessible(true);
698                                         }
699                                         LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "("
700                                                 + paramValue + ")");
701                                         m.invoke(toObj, paramValue);
702                                         if (!isAccessible) {
703                                             m.setAccessible(isAccessible);
704                                         }
705                                         foundValue = true;
706
707                                     } catch (Exception e) {
708                                         LOG.error("Caught exception trying to call " + toClass.getName() + "."
709                                                 + m.getName() + "() with Properties entry", e);
710                                     }
711                                 }
712                             } else if ("IpPrefix".equals(simpleName)) {
713                                 if ((paramValue != null) && (paramValue.length() > 0)) {
714                                     try {
715                                         IpPrefix ipPrefix = IpPrefixBuilder.getDefaultInstance(paramValue);
716                                         m.invoke(toObj, ipPrefix);
717                                         foundValue = true;
718                                     } catch (Exception e) {
719                                         LOG.error("Caught exception calling " + toClass.getName() + "." + m.getName()
720                                                 + "(" + paramValue + ")", e);
721                                     }
722                                 }
723                             } else if ("PortNumber".equals(simpleName)) {
724                                 if ((paramValue != null) && (paramValue.length() > 0)) {
725                                     try {
726                                         PortNumber portNumber = PortNumber.getDefaultInstance(paramValue);
727                                         m.invoke(toObj, portNumber);
728                                         foundValue = true;
729                                     } catch (Exception e) {
730                                         LOG.error("Caught exception calling " + toClass.getName() + "." + m.getName()
731                                                 + "(" + paramValue + ")", e);
732                                     }
733                                 }
734                             } else if ("Dscp".equals(simpleName)) {
735                                 if ((paramValue != null) && (paramValue.length() > 0)) {
736                                     try {
737                                         Dscp dscp = Dscp.getDefaultInstance(paramValue);
738                                         m.invoke(toObj, dscp);
739                                         foundValue = true;
740                                     } catch (Exception e) {
741                                         LOG.error("Caught exception calling " + toClass.getName() + "." + m.getName()
742                                                 + "(" + paramValue + ")", e);
743                                     }
744                                 }
745                             } else {
746                                 // setter expects a yang-generated class. Need
747                                 // to
748                                 // create a builder to set it.
749
750                                 String builderName = paramClass.getName() + "Builder";
751                                 Class builderClass = null;
752                                 Object builderObj = null;
753                                 Object paramObj = null;
754
755                                 Object constObj = null;
756
757                                 LOG.trace(m.getName() + " expects a yang-generated class - looking for builder "
758                                         + builderName);
759                                 try {
760                                     builderClass = Class.forName(builderName);
761                                     builderObj = builderClass.newInstance();
762                                     paramObj = toBuilder(props, propNamePfx, builderObj);
763                                 } catch (ClassNotFoundException e) {
764                                     LOG.info("Builder class {} not found ", builderName, e);
765                                     if (paramValue == null) {
766                                         try {
767                                             boolean isAccessible = m.isAccessible();
768                                             if (!isAccessible) {
769                                                 m.setAccessible(true);
770                                             }
771                                             LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName()
772                                                     + "(null)");
773                                             m.invoke(toObj, new Object[] {null});
774                                             if (!isAccessible) {
775                                                 m.setAccessible(isAccessible);
776                                             }
777                                             foundValue = true;
778
779                                         } catch (Exception e1) {
780                                             LOG.error("Caught exception trying to cally" + toClass.getName() + "."
781                                                     + m.getName() + "() with Properties entry", e1);
782                                         }
783                                     } else {
784                                         try {
785                                             // See if I can find a constructor I
786                                             // can
787                                             // use
788                                             Constructor[] constructors = paramClass.getConstructors();
789                                             // Is there a String constructor?
790                                             for (Constructor c : constructors) {
791                                                 Class[] cParms = c.getParameterTypes();
792                                                 if ((cParms != null) && (cParms.length == 1)) {
793                                                     if (String.class.isAssignableFrom(cParms[0])) {
794                                                         constObj = c.newInstance(paramValue);
795                                                     }
796                                                 }
797                                             }
798
799                                             if (constObj == null) {
800                                                 // Is there a Long constructor?
801                                                 for (Constructor c : constructors) {
802                                                     Class[] cParms = c.getParameterTypes();
803                                                     if ((cParms != null) && (cParms.length == 1)) {
804                                                         if (Long.class.isAssignableFrom(cParms[0])) {
805                                                             constObj = c.newInstance(Long.parseLong(paramValue));
806                                                         }
807                                                     }
808                                                 }
809
810                                             }
811
812                                             if (constObj == null) {
813
814                                                 // Last chance - see if
815                                                 // parameter class has a static
816                                                 // method
817                                                 // getDefaultInstance(String)
818                                                 try {
819                                                     Method gm =
820                                                             paramClass.getMethod("getDefaultInstance", String.class);
821
822                                                     int gmodifier = gm.getModifiers();
823                                                     if (Modifier.isStatic(gmodifier)) {
824                                                         // Invoke static
825                                                         // getDefaultInstance(String)
826                                                         paramObj = gm.invoke(null, paramValue);
827                                                     }
828
829                                                 } catch (Exception gme) {
830                                                     LOG.info("Unable to find static method getDefaultInstance for "
831                                                             + "class {}", paramClass.getSimpleName(), gme);
832                                                 }
833                                             }
834
835                                         } catch (Exception e1) {
836                                             LOG.warn(
837                                                     "Could not find a suitable constructor for " + paramClass.getName(),
838                                                     e1);
839                                         }
840
841                                         if (constObj == null) {
842                                             LOG.warn("Could not find builder class " + builderName
843                                                     + " and could not find a String or Long constructor or static "
844                                                     + "getDefaultInstance(String) - trying just to set passing paramValue");
845
846                                         }
847                                     }
848                                 } catch (Exception e) {
849                                     LOG.error("Caught exception trying to create builder " + builderName, e);
850                                 }
851
852                                 if (paramObj != null && builderClass != null) {
853
854                                     try {
855                                         Method buildMethod = builderClass.getMethod("build");
856                                         LOG.trace("Calling " + paramObj.getClass().getName() + "."
857                                                 + buildMethod.getName() + "()");
858                                         Object builtObj = buildMethod.invoke(paramObj);
859
860                                         boolean isAccessible = m.isAccessible();
861                                         if (!isAccessible) {
862                                             m.setAccessible(true);
863                                         }
864
865                                         LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "()");
866                                         m.invoke(toObj, builtObj);
867                                         if (!isAccessible) {
868                                             m.setAccessible(isAccessible);
869                                         }
870                                         foundValue = true;
871
872                                     } catch (Exception e) {
873                                         LOG.error("Caught exception trying to set Yang-generated class expected by"
874                                                 + toClass.getName() + "." + m.getName() + "() from Properties entry",
875                                                 e);
876                                     }
877                                 } else {
878                                     try {
879                                         boolean isAccessible = m.isAccessible();
880                                         if (!isAccessible) {
881                                             m.setAccessible(true);
882                                         }
883
884                                         if (constObj != null) {
885
886                                             LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "("
887                                                     + constObj.toString() + ")");
888                                             m.invoke(toObj, constObj);
889                                         } else {
890                                             LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "("
891                                                     + paramValue + ")");
892                                             m.invoke(toObj, paramValue);
893
894                                         }
895                                         if (!isAccessible) {
896                                             m.setAccessible(isAccessible);
897                                         }
898                                         foundValue = true;
899
900                                     } catch (Exception e) {
901                                         LOG.error("Caught exception trying to convert value returned by"
902                                                 + toClass.getName() + "." + m.getName() + "() to Properties entry", e);
903                                     }
904                                 }
905                             }
906                         }
907                     } else {
908
909                         // Setter's argument is not a yang-generated class. See
910                         // if it is a List.
911
912                         if (List.class.isAssignableFrom(paramClass)) {
913
914                             LOG.trace("Parameter class " + paramClass.getName() + " is a List");
915
916                             // Figure out what type of args are in List and pass
917                             // that to toList().
918
919                             Type paramType = m.getGenericParameterTypes()[0];
920                             Type elementType = ((ParameterizedType) paramType).getActualTypeArguments()[0];
921                             Object paramObj = new LinkedList();
922                             try {
923                                 paramObj = toList(props, propName, (List) paramObj, (Class) elementType);
924                             } catch (Exception e) {
925                                 LOG.error("Caught exception trying to create list expected as argument to {}.{}",
926                                         toClass.getName(), m.getName(), e);
927                             }
928
929                             if (paramObj != null) {
930                                 try {
931                                     boolean isAccessible = m.isAccessible();
932                                     if (!isAccessible) {
933                                         m.setAccessible(true);
934                                     }
935                                     LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "("
936                                             + paramValue + ")");
937                                     m.invoke(toObj, paramObj);
938                                     if (!isAccessible) {
939                                         m.setAccessible(isAccessible);
940                                     }
941                                     foundValue = true;
942
943                                 } catch (Exception e) {
944                                     LOG.error("Caught exception trying to convert List returned by" + toClass.getName()
945                                             + "." + m.getName() + "() to Properties entry", e);
946                                 }
947                             }
948                         } else {
949
950                             // Setter expects something that is not a List and
951                             // not yang-generated. Just pass the parameter value
952
953                             LOG.trace("Parameter class " + paramClass.getName()
954                                     + " is not a yang-generated class or a List");
955
956                             if ((paramValue != null) && (paramValue.length() > 0)) {
957
958                                 Object constObj = null;
959
960                                 try {
961                                     // See if I can find a constructor I can use
962                                     Constructor[] constructors = paramClass.getConstructors();
963                                     // Is there a String constructor?
964                                     for (Constructor c : constructors) {
965                                         Class[] cParms = c.getParameterTypes();
966                                         if ((cParms != null) && (cParms.length == 1)) {
967                                             if (String.class.isAssignableFrom(cParms[0])) {
968                                                 constObj = c.newInstance(paramValue);
969                                             }
970                                         }
971                                     }
972
973                                     if (constObj == null) {
974                                         // Is there a Long constructor?
975                                         for (Constructor c : constructors) {
976                                             Class[] cParms = c.getParameterTypes();
977                                             if ((cParms != null) && (cParms.length == 1)) {
978                                                 if (Long.class.isAssignableFrom(cParms[0])) {
979                                                     constObj = c.newInstance(Long.parseLong(paramValue));
980                                                 }
981                                             }
982                                         }
983
984                                     }
985
986                                     if (constObj != null) {
987                                         try {
988                                             LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "("
989                                                     + constObj + ")");
990                                             m.invoke(toObj, constObj);
991                                             foundValue = true;
992                                         } catch (Exception e2) {
993                                             LOG.error("Caught exception trying to call " + m.getName(), e2);
994                                         }
995                                     } else {
996                                         try {
997                                             boolean isAccessible = m.isAccessible();
998                                             if (!isAccessible) {
999                                                 m.setAccessible(true);
1000                                             }
1001                                             LOG.trace("Calling " + toObj.getClass().getName() + "." + m.getName() + "("
1002                                                     + paramValue + ")");
1003                                             m.invoke(toObj, paramValue);
1004                                             if (!isAccessible) {
1005                                                 m.setAccessible(isAccessible);
1006                                             }
1007                                             foundValue = true;
1008
1009                                         } catch (Exception e) {
1010                                             LOG.error("Caught exception trying to convert value returned by"
1011                                                     + toClass.getName() + "." + m.getName() + "() to Properties entry",
1012                                                     e);
1013                                         }
1014                                     }
1015                                 } catch (Exception e1) {
1016                                     LOG.warn("Could not find a suitable constructor for " + paramClass.getName(), e1);
1017                                 }
1018
1019                             }
1020                         }
1021                     }
1022                 } // End of section handling "setter" method
1023             } // End of loop through Methods
1024         } // End of section handling yang-generated class
1025
1026         if (foundValue) {
1027             return (toObj);
1028         } else {
1029             return (null);
1030         }
1031     }
1032
1033     public static void printPropertyList(PrintStream pstr, String pfx, Class toClass) {
1034         boolean foundValue = false;
1035
1036         LOG.trace("Analyzing " + toClass.getName() + " class : pfx " + pfx);
1037
1038         if (isYangGenerated(toClass) && (!Identifier.class.isAssignableFrom(toClass))) {
1039             // Class is yang generated.
1040             LOG.trace(toClass.getName() + " is a Yang-generated class");
1041
1042             if (toClass.getName().endsWith("Key")) {
1043                 if (Identifier.class.isAssignableFrom(toClass)) {
1044                     LOG.trace(Identifier.class.getName() + " is assignable from " + toClass.getName());
1045                 } else {
1046
1047                     LOG.trace(Identifier.class.getName() + " is NOT assignable from " + toClass.getName());
1048                 }
1049             }
1050
1051             String propNamePfx = null;
1052             if (pfx.endsWith("]")) {
1053                 propNamePfx = pfx;
1054             } else {
1055
1056                 if ((pfx != null) && (pfx.length() > 0)) {
1057                     propNamePfx = pfx + "." + toLowerHyphen(toClass.getSimpleName());
1058                 } else {
1059                     propNamePfx = toLowerHyphen(toClass.getSimpleName());
1060                 }
1061
1062                 if (propNamePfx.endsWith("-builder")) {
1063                     propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-builder".length());
1064                 }
1065
1066                 if (propNamePfx.endsWith("-impl")) {
1067                     propNamePfx = propNamePfx.substring(0, propNamePfx.length() - "-impl".length());
1068                 }
1069             }
1070
1071             // Iterate through getter methods to figure out values we need to
1072             // set
1073
1074             for (Method m : toClass.getMethods()) {
1075                 LOG.trace("Is " + m.getName() + " method a getter?");
1076                 if (isGetter(m)) {
1077                     LOG.trace(m.getName() + " is a getter");
1078                     Class returnClass = m.getReturnType();
1079
1080                     String fieldName = toLowerHyphen(m.getName().substring(3));
1081                     fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
1082
1083                     String propName = propNamePfx + "." + fieldName;
1084
1085                     // Is the return type a yang generated class?
1086                     if (isYangGenerated(returnClass)) {
1087                         // Is it an enum?
1088                         if (returnClass.isEnum()) {
1089
1090                             LOG.trace(m.getName() + " is an Enum");
1091                             pstr.print("\n\n     * " + propName);
1092
1093                         } else {
1094
1095                             String simpleName = returnClass.getSimpleName();
1096
1097                             if ("Ipv4Address".equals(simpleName) || "Ipv6Address".equals(simpleName)
1098                                     || "IpAddress".equals(simpleName) || "IpPrefix".equals(simpleName)
1099                                     || "PortNumber".equals(simpleName) || "Dscp".equals(simpleName)) {
1100                                 LOG.trace(m.getName() + " is an " + simpleName);
1101                                 pstr.print("\n\n     * " + propName);
1102                             } else {
1103                                 printPropertyList(pstr, propNamePfx, returnClass);
1104                             }
1105
1106                         }
1107                     } else {
1108
1109                         // Setter's argument is not a yang-generated class. See
1110                         // if it is a List.
1111
1112                         if (List.class.isAssignableFrom(returnClass)) {
1113
1114                             LOG.trace("Parameter class " + returnClass.getName() + " is a List");
1115
1116                             // Figure out what type of args are in List and pass
1117                             // that to toList().
1118
1119                             Type returnType = m.getGenericReturnType();
1120                             Type elementType = ((ParameterizedType) returnType).getActualTypeArguments()[0];
1121                             Class elementClass = (Class) elementType;
1122                             LOG.trace("Calling printPropertyList on list type (" + elementClass.getName()
1123                                     + "), pfx is (" + pfx + "), toClass is (" + toClass.getName() + ")");
1124                             printPropertyList(pstr,
1125                                     propNamePfx + "." + toLowerHyphen(elementClass.getSimpleName()) + "[]",
1126                                     elementClass);
1127
1128                         } else if (!returnClass.equals(Class.class)) {
1129
1130                             // Setter expects something that is not a List and
1131                             // not yang-generated. Just pass the parameter value
1132
1133                             LOG.trace("Parameter class " + returnClass.getName()
1134                                     + " is not a yang-generated class or a List");
1135
1136                             pstr.print("\n\n     * " + propName);
1137                         }
1138                     }
1139                 } // End of section handling "setter" method
1140             } // End of loop through Methods
1141         } // End of section handling yang-generated class
1142
1143     }
1144
1145     public static boolean isYangGenerated(Class c) {
1146         if (c == null) {
1147             return (false);
1148         } else {
1149             return (c.getName().startsWith("org.opendaylight.yang.gen."));
1150         }
1151     }
1152
1153     public static boolean isIpPrefix(Class c) {
1154
1155         if (c == null) {
1156             return (false);
1157         }
1158         if (!isIetfInet(c)) {
1159             return (false);
1160         }
1161         String simpleName = c.getSimpleName();
1162         return ("IpPrefix".equals(simpleName));
1163     }
1164
1165     public static boolean isIpv4Address(Class c) {
1166
1167         if (c == null) {
1168             return (false);
1169         }
1170         if (!isIetfInet(c)) {
1171             return (false);
1172         }
1173         String simpleName = c.getSimpleName();
1174         return ("Ipv4Address".equals(simpleName));
1175     }
1176
1177     public static boolean isIpv6Address(Class c) {
1178
1179         if (c == null) {
1180             return (false);
1181         }
1182         if (!isIetfInet(c)) {
1183             return (false);
1184         }
1185         String simpleName = c.getSimpleName();
1186         return ("Ipv6Address".equals(simpleName));
1187     }
1188
1189     public static boolean isIpAddress(Class c) {
1190
1191         if (c == null) {
1192             return (false);
1193         }
1194         if (!isIetfInet(c)) {
1195             return (false);
1196         }
1197         String simpleName = c.getSimpleName();
1198         return ("IpAddress".equals(simpleName));
1199     }
1200
1201     public static boolean isPortNumber(Class c) {
1202
1203         if (c == null) {
1204             return (false);
1205         }
1206         if (!isIetfInet(c)) {
1207             return (false);
1208         }
1209
1210         String simpleName = c.getSimpleName();
1211         return ("PortNumber".equals(simpleName));
1212     }
1213
1214     public static boolean isDscp(Class c) {
1215
1216         if (c == null) {
1217             return (false);
1218         }
1219         if (!isIetfInet(c)) {
1220             return (false);
1221         }
1222         String simpleName = c.getSimpleName();
1223         return ("Dscp".equals(simpleName));
1224     }
1225
1226     public static boolean isIetfInet(Class c) {
1227
1228         Package p = c.getPackage();
1229         if (p != null) {
1230             String pkgName = p.getName();
1231
1232             if ((pkgName != null) && (pkgName.indexOf("yang.ietf.inet.types") > -1)) {
1233                 return (true);
1234             }
1235         }
1236
1237         return (false);
1238     }
1239
1240     public static String toLowerHyphen(String inStr) {
1241         if (inStr == null) {
1242             return (null);
1243         }
1244
1245         String str = inStr.substring(0, 1).toLowerCase();
1246         if (inStr.length() > 1) {
1247             str = str + inStr.substring(1);
1248         }
1249
1250         String regex = "(([a-z0-9])([A-Z]))";
1251         String replacement = "$2-$3";
1252
1253         String retval = str.replaceAll(regex, replacement).toLowerCase();
1254
1255         LOG.trace("Converting " + inStr + " => " + str + " => " + retval);
1256         return (retval);
1257     }
1258
1259     // This is called when mapping the yang value back to a valid java enumeration
1260     public static String toJavaEnum(String inStr) {
1261         if (inStr == null) {
1262             return (null);
1263         } else if (inStr.length() == 0) {
1264             return (inStr);
1265         }
1266
1267         // This will strip out all periods, which cannot be in a java enum
1268         inStr = inStr.replaceAll("\\.", "");
1269
1270         String[] terms = inStr.split("-");
1271         StringBuffer sbuff = new StringBuffer();
1272
1273         // appends an _ if the string starts with a digit to make it a valid java enum
1274         if (Character.isDigit(inStr.charAt(0))) {
1275             sbuff.append('_');
1276         }
1277         // If the string contains hyphens it will convert the string to upperCamelCase without hyphens
1278         for (String term : terms) {
1279             sbuff.append(term.substring(0, 1).toUpperCase());
1280             if (term.length() > 1) {
1281                 sbuff.append(term.substring(1));
1282             }
1283         }
1284         return (sbuff.toString());
1285
1286     }
1287
1288     public static boolean isGetter(Method m) {
1289         if (m == null) {
1290             return (false);
1291         }
1292
1293         if (Modifier.isPublic(m.getModifiers()) && (m.getParameterTypes().length == 0)) {
1294             if (m.getName().matches("^get[A-Z].*") && !m.getReturnType().equals(void.class)) {
1295                 if (!"getClass".equals(m.getName())) {
1296                     return (true);
1297                 }
1298             }
1299
1300             if (m.getName().matches("^get[A-Z].*") && m.getReturnType().equals(boolean.class)) {
1301                 return (true);
1302             }
1303
1304             if (m.getName().matches("^is[A-Z].*") && m.getReturnType().equals(Boolean.class)) {
1305                 return (true);
1306             }
1307         }
1308
1309         return (false);
1310     }
1311
1312     public static boolean isSetter(Method m) {
1313         if (m == null) {
1314             return (false);
1315         }
1316
1317         if (Modifier.isPublic(m.getModifiers()) && (m.getParameterTypes().length == 1)) {
1318             if (m.getName().matches("^set[A-Z].*")) {
1319                 Class[] paramTypes = m.getParameterTypes();
1320                 if (paramTypes[0].isAssignableFrom(Identifier.class)
1321                         || Identifier.class.isAssignableFrom(paramTypes[0])) {
1322                     return (false);
1323                 } else {
1324                     return (true);
1325                 }
1326             }
1327
1328         }
1329
1330         return (false);
1331     }
1332
1333     public static String getFullPropertiesPath(String propertiesFileName) {
1334         return "/opt/bvc/controller/configuration/" + propertiesFileName;
1335     }
1336
1337     // This is called when mapping a valid java enumeration back to the yang model value
1338     public static String mapEnumeratedValue(String propertyName, String propertyValue) {
1339         LOG.info("mapEnumeratedValue called with propertyName=" + propertyName + " and value=" + propertyValue);
1340         String mappingKey = "yang." + propertyName + "." + propertyValue;
1341         if (yangMappingProperties.containsKey(mappingKey)) {
1342             return (yangMappingProperties.getProperty(mappingKey));
1343         } else {
1344             LOG.info("yangMappingProperties did not contain the key " + mappingKey + " returning the original value.");
1345             return propertyValue;
1346         }
1347     }
1348 }