Set Binding RPCs cost to 1
[mdsal.git] / binding2 / mdsal-binding2-util / src / main / java / org / opendaylight / mdsal / binding2 / util / BindingMapping.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.mdsal.binding2.util;
10
11 import com.google.common.annotations.Beta;
12 import com.google.common.base.CharMatcher;
13 import com.google.common.base.Preconditions;
14 import com.google.common.base.Splitter;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.collect.Interner;
17 import com.google.common.collect.Interners;
18 import java.text.SimpleDateFormat;
19 import java.util.Set;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22 import org.opendaylight.yangtools.concepts.SemVer;
23 import org.opendaylight.yangtools.yang.model.api.Module;
24
25 /**
26  * Standard Util class that provides generated Java related functionality
27  */
28 @Beta
29 public final class BindingMapping {
30
31     public static final Set<String> JAVA_RESERVED_WORDS = ImmutableSet.of("abstract", "assert", "boolean", "break",
32             "byte", "case", "catch", "char", "class", "const", "continue", "default", "double", "do", "else", "enum",
33             "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof",
34             "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return",
35             "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient",
36             "true", "try", "void", "volatile", "while");
37
38     public static final String QNAME_STATIC_FIELD_NAME = "QNAME";
39     public static final String PACKAGE_PREFIX = "org.opendaylight.yang.gen.v2";
40
41     private static final Splitter DOT_SPLITTER = Splitter.on('.');
42     private static final Interner<String> PACKAGE_INTERNER = Interners.newWeakInterner();
43     private static final Splitter CAMEL_SPLITTER = Splitter.on(CharMatcher.anyOf(" _.-/").precomputed())
44             .omitEmptyStrings().trimResults();
45     private static final Pattern COLON_SLASH_SLASH = Pattern.compile("://", Pattern.LITERAL);
46     private static final String QUOTED_DOT = Matcher.quoteReplacement(".");
47     public static final String MODULE_INFO_CLASS_NAME = "$YangModuleInfoImpl";
48     public static final String MODEL_BINDING_PROVIDER_CLASS_NAME = "$YangModelBindingProvider";
49     public static final String PATTERN_CONSTANT_NAME = "PATTERN_CONSTANTS";
50     public static final String MEMBER_PATTERN_LIST = "patterns";
51
52     private static final ThreadLocal<SimpleDateFormat> PACKAGE_DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
53
54         @Override
55         protected SimpleDateFormat initialValue() {
56             return new SimpleDateFormat("yyMMdd");
57         }
58
59         @Override
60         public void set(final SimpleDateFormat value) {
61             throw new UnsupportedOperationException();
62         }
63     };
64
65     private BindingMapping() {
66         throw new UnsupportedOperationException("Utility class");
67     }
68
69     public static String getRootPackageName(final Module module) {
70         Preconditions.checkArgument(module != null, "Module must not be null");
71         Preconditions.checkArgument(module.getRevision() != null, "Revision must not be null");
72         Preconditions.checkArgument(module.getNamespace() != null, "Namespace must not be null");
73
74         final StringBuilder packageNameBuilder = new StringBuilder();
75         packageNameBuilder.append(PACKAGE_PREFIX);
76         packageNameBuilder.append('.');
77
78         String namespace = module.getNamespace().toString();
79         namespace = COLON_SLASH_SLASH.matcher(namespace).replaceAll(QUOTED_DOT);
80
81         final char[] chars = namespace.toCharArray();
82         for (int i = 0; i < chars.length; ++i) {
83             switch (chars[i]) {
84                 case '/':
85                 case ':':
86                 case '-':
87                 case '@':
88                 case '$':
89                 case '#':
90                 case '\'':
91                 case '*':
92                 case '+':
93                 case ',':
94                 case ';':
95                 case '=':
96                     chars[i] = '.';
97                     break;
98                 default:
99                     // no-op, any other character is kept as it is
100             }
101         }
102
103         packageNameBuilder.append(chars);
104         if (chars[chars.length - 1] != '.') {
105             packageNameBuilder.append('.');
106         }
107
108         final SemVer semVer = module.getSemanticVersion();
109         if (semVer != null) {
110             packageNameBuilder.append(semVer.toString());
111         } else {
112             packageNameBuilder.append("rev");
113             packageNameBuilder.append(PACKAGE_DATE_FORMAT.get().format(module.getRevision()));
114         }
115         return normalizePackageName(packageNameBuilder.toString());
116     }
117
118     public static String normalizePackageName(final String packageName) {
119         if (packageName == null) {
120             return null;
121         }
122
123         final StringBuilder builder = new StringBuilder();
124         boolean first = true;
125
126         for (String p : DOT_SPLITTER.split(packageName.toLowerCase())) {
127             if (first) {
128                 first = false;
129             } else {
130                 builder.append('.');
131             }
132
133             //FIXME: don't use underscore in v2
134             if (Character.isDigit(p.charAt(0)) || BindingMapping.JAVA_RESERVED_WORDS.contains(p)) {
135                 builder.append('_');
136             }
137             builder.append(p);
138         }
139
140         // Prevent duplication of input string
141         return PACKAGE_INTERNER.intern(builder.toString());
142     }
143
144     public static String getClassName(final String localName) {
145         Preconditions.checkArgument(localName != null, "Name should not be null.");
146         return toFirstUpper(toCamelCase(localName));
147     }
148
149     private static String toCamelCase(final String rawString) {
150         Preconditions.checkArgument(rawString != null, "String should not be null");
151         Iterable<String> components = CAMEL_SPLITTER.split(rawString);
152         StringBuilder builder = new StringBuilder();
153         for (String comp : components) {
154             builder.append(toFirstUpper(comp));
155         }
156         return checkNumericPrefix(builder.toString());
157     }
158
159     private static String checkNumericPrefix(final String rawString) {
160         if (rawString == null || rawString.isEmpty()) {
161             return rawString;
162         }
163         char firstChar = rawString.charAt(0);
164         if (firstChar >= '0' && firstChar <= '9') {
165             return "_" + rawString;
166         } else {
167             return rawString;
168         }
169     }
170
171     /**
172      * Returns the {@link String} {@code s} with an
173      * {@link Character#isUpperCase(char) upper case} first character. This
174      * function is null-safe.
175      *
176      * @param s
177      *            the string that should get an upper case first character. May
178      *            be <code>null</code>.
179      * @return the {@link String} {@code s} with an upper case first character
180      *         or <code>null</code> if the input {@link String} {@code s} was
181      *         <code>null</code>.
182      */
183     public static String toFirstUpper(final String s) {
184         if (s == null || s.length() == 0) {
185             return s;
186         }
187         if (Character.isUpperCase(s.charAt(0))) {
188             return s;
189         }
190         if (s.length() == 1) {
191             return s.toUpperCase();
192         }
193         return s.substring(0, 1).toUpperCase() + s.substring(1);
194     }
195
196     //TODO: further implementation of static util methods...
197
198 }