--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.binding;
+
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableSet;
+import static com.google.common.base.Preconditions.*;
+
+public final class BindingMapping {
+
+ public static final String VERSION = "0.6";
+
+ public static final Set<String> JAVA_RESERVED_WORDS = ImmutableSet.of("abstract", "assert", "boolean", "break",
+ "byte", "case", "catch", "char", "class", "const", "continue", "default", "double", "do", "else", "enum",
+ "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof",
+ "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return",
+ "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient",
+ "true", "try", "void", "volatile", "while");
+
+ public static final String DATA_ROOT_SUFFIX = "Data";
+ public static final String RPC_SERVICE_SUFFIX = "Service";
+ public static final String NOTIFICATION_LISTENER_SUFFIX = "Listener";
+ public static final String QNAME_STATIC_FIELD_NAME = "QNAME";
+
+ private static final Splitter SPACE_SPLITTER = Splitter.on(" ").omitEmptyStrings().trimResults();
+
+ public static final String getMethodName(QName name) {
+ checkArgument(name != null, "Name should not be null.");
+ return toFirstLower(toCamelCase(name.getLocalName()));
+ }
+
+ public static final String getClassName(String localName) {
+ return toFirstUpper(toCamelCase(localName));
+ }
+
+ public static final String getClassName(QName name) {
+ checkArgument(name != null, "Name should not be null.");
+ return toFirstUpper(toCamelCase(name.getLocalName()));
+ }
+
+ private static final String toCamelCase(String rawString) {
+ checkArgument(rawString != null, "String should not be null");
+ Iterable<String> components = SPACE_SPLITTER.split(rawString.replace('-', ' ').replace('_', ' '));
+ StringBuilder builder = new StringBuilder();
+ for (String comp : components) {
+ builder.append(toFirstUpper(comp));
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns the {@link String} {@code s} with an
+ * {@link Character#isUpperCase(char) upper case} first character. This
+ * function is null-safe.
+ *
+ * @param s
+ * the string that should get an upper case first character. May
+ * be <code>null</code>.
+ * @return the {@link String} {@code s} with an upper case first character
+ * or <code>null</code> if the input {@link String} {@code s} was
+ * <code>null</code>.
+ */
+ private static String toFirstUpper(String s) {
+ if (s == null || s.length() == 0)
+ return s;
+ if (Character.isUpperCase(s.charAt(0)))
+ return s;
+ if (s.length() == 1)
+ return s.toUpperCase();
+ return s.substring(0, 1).toUpperCase() + s.substring(1);
+ }
+
+ /**
+ * Returns the {@link String} {@code s} with an
+ * {@link Character#isLowerCase(char) lower case} first character. This
+ * function is null-safe.
+ *
+ * @param s
+ * the string that should get an lower case first character. May
+ * be <code>null</code>.
+ * @return the {@link String} {@code s} with an lower case first character
+ * or <code>null</code> if the input {@link String} {@code s} was
+ * <code>null</code>.
+ */
+ private static String toFirstLower(String s) {
+ if (s == null || s.length() == 0)
+ return s;
+ if (Character.isLowerCase(s.charAt(0)))
+ return s;
+ if (s.length() == 1)
+ return s.toLowerCase();
+ return s.substring(0, 1).toLowerCase() + s.substring(1);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.binding.util;
+
+import java.lang.reflect.Field;
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.common.QName;
+
+import com.google.common.base.Optional;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+public class BindingReflections {
+
+ private static final long EXPIRATION_TIME = 60;
+
+ private static final LoadingCache<Class<?>, Optional<QName>> classToQName = CacheBuilder.newBuilder() //
+ .weakKeys() //
+ .expireAfterAccess(EXPIRATION_TIME, TimeUnit.SECONDS) //
+ .build(new ClassToQNameLoader());
+
+ /**
+ *
+ * @param augmentation
+ * {@link Augmentation} subclass for which we want to determine
+ * augmentation target.
+ * @return Augmentation target - class which augmentation provides
+ * additional extensions.
+ */
+ public static Class<? extends Augmentable<?>> findAugmentationTarget(
+ final Class<? extends Augmentation<?>> augmentation) {
+ return ClassLoaderUtils.findFirstGenericArgument(augmentation, Augmentation.class);
+ }
+
+ /**
+ *
+ * @param augmentation
+ * {@link Augmentation} subclass for which we want to determine
+ * augmentation target.
+ * @return Augmentation target - class which augmentation provides
+ * additional extensions.
+ */
+ public static Class<?> findHierarchicalParent(final Class<? extends ChildOf<?>> childClass) {
+ return ClassLoaderUtils.findFirstGenericArgument(childClass, ChildOf.class);
+ }
+
+ /**
+ *
+ * @param augmentation
+ * {@link Augmentation} subclass for which we want to determine
+ * augmentation target.
+ * @return Augmentation target - class which augmentation provides
+ * additional extensions.
+ */
+ public static Class<?> findHierarchicalParent(DataObject childClass) {
+ if (childClass instanceof ChildOf) {
+ return ClassLoaderUtils.findFirstGenericArgument(childClass.getImplementedInterface(), ChildOf.class);
+ }
+ return null;
+ }
+
+ public static final QName findQName(Class<? extends DataContainer> dataType) {
+ return classToQName.getUnchecked(dataType).orNull();
+ }
+
+ private static class ClassToQNameLoader extends CacheLoader<Class<?>, Optional<QName>> {
+
+ @Override
+ public Optional<QName> load(Class<?> key) throws Exception {
+ try {
+ Field field = key.getField(BindingMapping.QNAME_STATIC_FIELD_NAME);
+ Object obj = field.get(null);
+ if (obj instanceof QName) {
+ return Optional.of((QName) obj);
+ }
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ // NOOP
+ }
+ return Optional.absent();
+ }
+ }
+
+}