import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder
import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl
-import org.opendaylight.yangtools.yang.common.QName\r
-\r
+import org.opendaylight.yangtools.yang.common.QName\rimport org.opendaylight.yangtools.yang.binding.BindingMapping
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilderBase
+
public class BindingGeneratorImpl implements BindingGenerator {
private final Map<Module, ModuleContext> genCtx = new HashMap()
interfaceBuilder.addImplementsType(Types.typeForClass(RpcService));
for (rpc : rpcDefinitions) {
if (rpc !== null) {
- val rpcName = parseToClassName(rpc.QName.localName);
+ val rpcName = BindingMapping.getClassName(rpc.QName);
val rpcMethodName = parseToValidParamName(rpcName);
val method = interfaceBuilder.addMethod(rpcMethodName);
val input = rpc.input;
return;
}
val packageName = packageNameForGeneratedType(basePackageName, identity.path);
- val genTypeName = parseToClassName(identity.QName.localName);
+ val genTypeName = BindingMapping.getClassName(identity.QName);
val newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
val baseIdentity = identity.baseIdentity;
if (baseIdentity === null) {
} else {
val baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
val returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
- val returnTypeName = parseToClassName(baseIdentity.QName.localName);
+ val returnTypeName = BindingMapping.getClassName(baseIdentity.QName);
val gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName).toInstance();
newType.setExtendsType(gto);
}
newType.setAbstract(true);\r
val qname = identity.QName;\r
- newType.addConstant(QName.typeForClass,"QNAME",'''\r
- org.opendaylight.yangtools.yang.common.QName.create("«qname.namespace»","«qname.formattedRevision»","«qname.localName»")\r
- ''');
+ \r
+ newType.qnameConstant(BindingMapping.QNAME_STATIC_FIELD_NAME,qname);\r
+
genCtx.get(module).addIdentityType(identity.QName,newType)
+ }\r
+ \r
+ private static def qnameConstant(GeneratedTypeBuilderBase<?> toBuilder, String constantName, QName name) {
+ toBuilder.addConstant(QName.typeForClass,constantName,'''\r
+ org.opendaylight.yangtools.yang.common.QName.create("«name.namespace»","«name.formattedRevision»","«name.localName»")\r
+ ''');
}
/**\r
* @return enumeration builder which contais data from\r
* <code>enumTypeDef</code>\r
*/
- private def EnumBuilder resolveInnerEnumFromTypeDefinition(EnumTypeDefinition enumTypeDef, String enumName,
+ private def EnumBuilder resolveInnerEnumFromTypeDefinition(EnumTypeDefinition enumTypeDef, QName enumName,
GeneratedTypeBuilder typeBuilder) {
if ((enumTypeDef !== null) && (typeBuilder !== null) && (enumTypeDef.QName !== null) &&
(enumTypeDef.QName.localName !== null)) {
- val enumerationName = parseToClassName(enumName);
+ val enumerationName = BindingMapping.getClassName(enumName);
val enumBuilder = typeBuilder.addEnumeration(enumerationName);
enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
return enumBuilder;
private def GeneratedTypeBuilder moduleTypeBuilder(Module module, String postfix) {
checkArgument(module !== null, "Module reference cannot be NULL.");
val packageName = moduleNamespaceToPackageName(module);
- val moduleName = parseToClassName(module.name) + postfix;
+ val moduleName = BindingMapping.getClassName(module.name) + postfix;
return new GeneratedTypeBuilderImpl(packageName, moduleName);
}
val augIdentifier = getAugmentIdentifier(augSchema.unknownSchemaNodes);
val augTypeName = if (augIdentifier !== null) {
- parseToClassName(augIdentifier)
+ BindingMapping.getClassName(augIdentifier)
} else {
augGenTypeName(augmentBuilders, targetTypeRef.name);
}
if (typeDef instanceof EnumTypeDefinition) {
returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
val enumTypeDef = typeDef as EnumTypeDefinition;
- val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName, typeBuilder);
+ val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.QName, typeBuilder);
if (enumBuilder !== null) {
returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name);
}
(typeProvider as TypeProviderImpl).putReferencedType(leaf.path, returnType);
} else if (typeDef instanceof UnionType) {
- val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
+ val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
if (genTOBuilder !== null) {
returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
}
} else if (typeDef instanceof BitsTypeDefinition) {
- val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
+ val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
if (genTOBuilder !== null) {
returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
}
val Class<RoutingContext> clazz = typeof(RoutingContext);
val AnnotationTypeBuilder rc = getter.addAnnotation(clazz.package.name, clazz.simpleName);
val packageName = packageNameForGeneratedType(basePackageName, identity.path);
- val genTypeName = parseToClassName(identity.QName.localName);
+ val genTypeName = BindingMapping.getClassName(identity.QName.localName);
rc.addParameter("value", packageName + "." + genTypeName + ".class");
}
}
*/
private def boolean resolveLeafListSchemaNode(GeneratedTypeBuilder typeBuilder, LeafListSchemaNode node) {
if ((node !== null) && (typeBuilder !== null)) {
- val nodeName = node.QName.localName;
+ val nodeName = node.QName;
var String nodeDesc = node.description;
if (nodeDesc === null) {
nodeDesc = "";
returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name);\r
(typeProvider as TypeProviderImpl).putReferencedType(node.path, returnType);\r
} else if (typeDef instanceof UnionType) {\r
- val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, nodeName, node, parentModule);\r
+ val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule);\r
returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);\r
} else if (typeDef instanceof BitsTypeDefinition) {\r
- val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, nodeName, node, parentModule);\r
+ val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule);\r
returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);\r
} else {\r
val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);\r
}\r
val listType = Types.listTypeFor(returnType);
- constructGetter(typeBuilder, nodeName, nodeDesc, listType);
+ constructGetter(typeBuilder, nodeName.localName, nodeDesc, listType);
return true;
}
}
Type parent) {
val it = addRawInterfaceDefinition(packageName, schemaNode, "");\r
val qname = schemaNode.QName;
- addConstant(QName.typeForClass,"QNAME",'''\r
- org.opendaylight.yangtools.yang.common.QName.create("«qname.namespace»","«qname.formattedRevision»","«qname.localName»")\r
- ''');\r
+ qnameConstant(BindingMapping.QNAME_STATIC_FIELD_NAME,schemaNode.QName);\r
if (parent === null) {
addImplementsType(DATA_OBJECT);
} else {
var String genTypeName;
if (prefix === null) {
- genTypeName = parseToClassName(schemaNodeName);
+ genTypeName = BindingMapping.getClassName(schemaNodeName);
} else {
- genTypeName = prefix + parseToClassName(schemaNodeName);
+ genTypeName = prefix + BindingMapping.getClassName(schemaNodeName);
}
//FIXME: Validation of name conflict\r
} else {
method.append("get");
}
- method.append(parseToClassName(localName));
+ method.append(BindingMapping.getClassName(localName));
return method.toString();
}
var GeneratedTOBuilder genTOBuilder = null;
if ((list.keyDefinition !== null) && (!list.keyDefinition.isEmpty())) {
val listName = list.QName.localName + "Key";
- val String genTOName = parseToClassName(listName);
+ val String genTOName = BindingMapping.getClassName(listName);
genTOBuilder = new GeneratedTOBuilderImpl(packageName, genTOName);
}
return genTOBuilder;
* @return generated TO builder for <code>typeDef</code>\r
*/
private def GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
- String leafName, DataSchemaNode leaf, Module parentModule) {
- val classNameFromLeaf = parseToClassName(leafName);
+ DataSchemaNode leaf, Module parentModule) {
+ val classNameFromLeaf = BindingMapping.getClassName(leaf.QName);
val List<GeneratedTOBuilder> genTOBuilders = new ArrayList();
val packageName = typeBuilder.fullyQualifiedName;
if (typeDef instanceof UnionTypeDefinition) {
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder;
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.TypeMemberBuilder;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
/**
* Array of strings values which represents JAVA reserved words.
*/
+ @Deprecated
private static final String[] SET_VALUES = new String[] { "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",
/**
* Hash set of words which are reserved in JAVA language.
*/
+ @Deprecated
private static final Set<String> JAVA_RESERVED_WORDS = new HashSet<String>(Arrays.asList(SET_VALUES));
/**
* JAVA class name
* @return string which is in accordance with best practices for JAVA class
* name.
+ *
+ * @deprecated Use {@link BindingMapping#getClassName(QName)} instead.
*/
+ @Deprecated
public static String parseToClassName(String token) {
return parseToCamelCase(token, true);
}
+/*
+ * 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;
-public interface BindingCodec<P,I> extends BindingSerializer<P, I>, BindingDeserializer<I, P> {
+import org.opendaylight.yangtools.concepts.Codec;
+
+public interface BindingCodec<P, I> extends //
+ BindingSerializer<P, I>, //
+ BindingDeserializer<I, P>, //
+ Codec<P, I> {
@Override
public P serialize(I input);
-
+
@Override
public I deserialize(P input);
}
+/*
+ * 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;
public interface BindingDeserializer<P,I> {
--- /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);
+ }
+}
+/*
+ * 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;
public interface BindingSerializer<P,I> {
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.concepts.Path;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
}
public InstanceIdentifier(List<PathArgument> path, Class<T> type) {
- this.path = Collections.<PathArgument> unmodifiableList(new ArrayList<>(path));
+ this.path = ImmutableList.copyOf(path);
this.targetType = type;
}
--- /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.io.ObjectInputStream.GetField;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.zip.Checksum;
+
+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.BaseIdentity;
+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.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
+
+import static com.google.common.base.Preconditions.*;
+
+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<?> 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();
+ }
+ }
+
+ public static boolean isRpcMethod(Method possibleMethod) {
+ return possibleMethod != null &&
+ RpcService.class.isAssignableFrom(possibleMethod.getDeclaringClass())
+ && Future.class.isAssignableFrom(possibleMethod.getReturnType())
+ && possibleMethod.getParameterTypes().length <= 1;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static Optional<Class<?>> resolveRpcOutputClass(Method targetMethod) {
+ checkState(isRpcMethod(targetMethod),"Supplied method is not Rpc invocation method");
+ Type futureType = targetMethod.getGenericReturnType();
+ Type rpcResultType = ClassLoaderUtils.getFirstGenericParameter(futureType);
+ Type rpcResultArgument = ClassLoaderUtils.getFirstGenericParameter(rpcResultType);
+ if(rpcResultArgument instanceof Class && !Void.class.equals(rpcResultArgument)) {
+ return Optional.<Class<?>>of((Class) rpcResultArgument);
+ }
+ return Optional.absent();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Optional<Class<? extends DataContainer>> resolveRpcInputClass(Method targetMethod) {
+ @SuppressWarnings("rawtypes")
+ Class[] types = targetMethod.getParameterTypes();
+ if(types.length == 0) {
+ return Optional.absent();
+ }
+ if(types.length == 1) {
+ return Optional.<Class<? extends DataContainer>>of(types[0]);
+ }
+ throw new IllegalArgumentException("Method has 2 or more arguments.");
+ }
+
+ public static QName getQName(Class<? extends BaseIdentity> context) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}