import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import com.google.common.util.concurrent.UncheckedExecutionException;
import org.opendaylight.yangtools.util.ClassLoaderUtils;
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.DataRoot;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.Notification;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
-final class SchemaRootCodecContext extends DataContainerCodecContext<SchemaContext> {
+final class SchemaRootCodecContext<D extends DataObject> extends DataContainerCodecContext<D,SchemaContext> {
- private final LoadingCache<Class<?>, DataContainerCodecContext<?>> childrenByClass = CacheBuilder.newBuilder()
- .build(new CacheLoader<Class<?>, DataContainerCodecContext<?>>() {
+ private final LoadingCache<Class<?>, DataContainerCodecContext<?,?>> childrenByClass = CacheBuilder.newBuilder()
+ .build(new CacheLoader<Class<?>, DataContainerCodecContext<?,?>>() {
@Override
- public DataContainerCodecContext<?> load(final Class<?> key) {
+ public DataContainerCodecContext<?,?> load(final Class<?> key) {
return createDataTreeChildContext(key);
}
});
- private final LoadingCache<Class<?>, ContainerNodeCodecContext> rpcDataByClass = CacheBuilder.newBuilder().build(
- new CacheLoader<Class<?>, ContainerNodeCodecContext>() {
+ private final LoadingCache<Class<?>, ContainerNodeCodecContext<?>> rpcDataByClass = CacheBuilder.newBuilder().build(
+ new CacheLoader<Class<?>, ContainerNodeCodecContext<?>>() {
@Override
- public ContainerNodeCodecContext load(final Class<?> key) {
+ public ContainerNodeCodecContext<?> load(final Class<?> key) {
return createRpcDataContext(key);
}
});
- private final LoadingCache<Class<?>, NotificationCodecContext> notificationsByClass = CacheBuilder.newBuilder()
- .build(new CacheLoader<Class<?>, NotificationCodecContext>() {
+ private final LoadingCache<Class<?>, NotificationCodecContext<?>> notificationsByClass = CacheBuilder.newBuilder()
+ .build(new CacheLoader<Class<?>, NotificationCodecContext<?>>() {
@Override
- public NotificationCodecContext load(final Class<?> key) {
+ public NotificationCodecContext<?> load(final Class<?> key) {
return createNotificationDataContext(key);
}
});
- private final LoadingCache<QName, DataContainerCodecContext<?>> childrenByQName = CacheBuilder.newBuilder().build(
- new CacheLoader<QName, DataContainerCodecContext<?>>() {
+ private final LoadingCache<QName, DataContainerCodecContext<?,?>> childrenByQName = CacheBuilder.newBuilder().build(
+ new CacheLoader<QName, DataContainerCodecContext<?,?>>() {
+ @SuppressWarnings("unchecked")
@Override
- public DataContainerCodecContext<?> load(final QName qname) {
+ public DataContainerCodecContext<?,?> load(final QName qname) {
final DataSchemaNode childSchema = schema().getDataChildByName(qname);
- Preconditions.checkArgument(childSchema != null, "Argument %s is not valid child of %s", qname,
- schema());
-
- if (childSchema instanceof DataNodeContainer || childSchema instanceof ChoiceNode) {
- final Class<?> childCls = factory().getRuntimeContext().getClassForSchema(childSchema);
- return getStreamChild(childCls);
+ childNonNull(childSchema, qname,"Argument %s is not valid child of %s", qname,schema());
+ if (childSchema instanceof DataNodeContainer || childSchema instanceof ChoiceSchemaNode) {
+ @SuppressWarnings("rawtypes")
+ final Class childCls = factory().getRuntimeContext().getClassForSchema(childSchema);
+ return streamChild(childCls);
} else {
throw new UnsupportedOperationException("Unsupported child type " + childSchema.getClass());
}
}
});
- private final LoadingCache<SchemaPath, ContainerNodeCodecContext> rpcDataByPath = CacheBuilder.newBuilder().build(
- new CacheLoader<SchemaPath, ContainerNodeCodecContext>() {
+ private final LoadingCache<SchemaPath, ContainerNodeCodecContext<?>> rpcDataByPath = CacheBuilder.newBuilder().build(
+ new CacheLoader<SchemaPath, ContainerNodeCodecContext<?>>() {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
}
});
- private final LoadingCache<SchemaPath, NotificationCodecContext> notificationsByPath = CacheBuilder.newBuilder()
- .build(new CacheLoader<SchemaPath, NotificationCodecContext>() {
+ private final LoadingCache<SchemaPath, NotificationCodecContext<?>> notificationsByPath = CacheBuilder.newBuilder()
+ .build(new CacheLoader<SchemaPath, NotificationCodecContext<?>>() {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
* CodecContextFactory
* @return
*/
- static SchemaRootCodecContext create(final CodecContextFactory factory) {
+ static SchemaRootCodecContext<?> create(final CodecContextFactory factory) {
final DataContainerCodecPrototype<SchemaContext> prototype = DataContainerCodecPrototype.rootPrototype(factory);
- return new SchemaRootCodecContext(prototype);
+ return new SchemaRootCodecContext<>(prototype);
}
+
+ @SuppressWarnings("unchecked")
@Override
- protected DataContainerCodecContext<?> getStreamChild(final Class<?> childClass) {
- return childrenByClass.getUnchecked(childClass);
+ public <DV extends DataObject> DataContainerCodecContext<DV, ?> streamChild(final Class<DV> childClass)
+ throws IllegalArgumentException {
+ /* FIXME: This is still not solved for RPCs
+ * TODO: Probably performance wise RPC, Data and Notification loading cache
+ * should be merge for performance resons. Needs microbenchmark to
+ * determine which is faster (keeping them separate or in same cache).
+ */
+ if (Notification.class.isAssignableFrom(childClass)) {
+ return (DataContainerCodecContext<DV, ?>) getNotification((Class<? extends Notification>)childClass);
+ }
+ return (DataContainerCodecContext<DV, ?>) getOrRethrow(childrenByClass,childClass);
}
@Override
- protected Optional<DataContainerCodecContext<?>> getPossibleStreamChild(final Class<?> childClass) {
+ public <E extends DataObject> Optional<DataContainerCodecContext<E,?>> possibleStreamChild(final Class<E> childClass) {
throw new UnsupportedOperationException("Not supported");
}
@Override
- protected NodeCodecContext getYangIdentifierChild(final PathArgument arg) {
- return childrenByQName.getUnchecked(arg.getNodeType());
+ public DataContainerCodecContext<?,?> yangPathArgumentChild(final PathArgument arg) {
+ return getOrRethrow(childrenByQName,arg.getNodeType());
}
@Override
- protected Object dataFromNormalizedNode(final NormalizedNode<?, ?> normalizedNode) {
- throw new UnsupportedOperationException("Could not create Binding data representation for root");
+ public D deserialize(final NormalizedNode<?, ?> normalizedNode) {
+ throw new UnsupportedOperationException(
+ "Could not create Binding data representation for root");
}
- ContainerNodeCodecContext getRpc(final Class<? extends DataContainer> rpcInputOrOutput) {
- return rpcDataByClass.getUnchecked(rpcInputOrOutput);
+
+ ContainerNodeCodecContext<?> getRpc(final Class<? extends DataContainer> rpcInputOrOutput) {
+ return getOrRethrow(rpcDataByClass, rpcInputOrOutput);
}
- NotificationCodecContext getNotification(final Class<? extends Notification> notification) {
- return notificationsByClass.getUnchecked(notification);
+ NotificationCodecContext<?> getNotification(final Class<? extends Notification> notification) {
+ return getOrRethrow(notificationsByClass, notification);
}
- NotificationCodecContext getNotification(final SchemaPath notification) {
- return notificationsByPath.getUnchecked(notification);
+ NotificationCodecContext<?> getNotification(final SchemaPath notification) {
+ return getOrRethrow(notificationsByPath, notification);
}
- ContainerNodeCodecContext getRpc(final SchemaPath notification) {
- return rpcDataByPath.getUnchecked(notification);
+ ContainerNodeCodecContext<?> getRpc(final SchemaPath notification) {
+ return getOrRethrow(rpcDataByPath, notification);
}
- private DataContainerCodecContext<?> createDataTreeChildContext(final Class<?> key) {
+ private DataContainerCodecContext<?,?> createDataTreeChildContext(final Class<?> key) {
final Class<Object> parent = ClassLoaderUtils.findFirstGenericArgument(key, ChildOf.class);
- Preconditions.checkArgument(DataRoot.class.isAssignableFrom(parent));
+ IncorrectNestingException.check(DataRoot.class.isAssignableFrom(parent), "Class %s is not top level item.", key);
final QName qname = BindingReflections.findQName(key);
- final DataSchemaNode childSchema = schema().getDataChildByName(qname);
+ final DataSchemaNode childSchema = childNonNull(schema().getDataChildByName(qname),key,"%s is not top-level item.",key);
return DataContainerCodecPrototype.from(key, childSchema, factory()).get();
}
- private ContainerNodeCodecContext createRpcDataContext(final Class<?> key) {
+ private ContainerNodeCodecContext<?> createRpcDataContext(final Class<?> key) {
Preconditions.checkArgument(DataContainer.class.isAssignableFrom(key));
final QName qname = BindingReflections.findQName(key);
final QNameModule module = qname.getModule();
Preconditions.checkArgument(rpc != null, "Supplied class %s is not valid RPC class.", key);
final ContainerSchemaNode schema = SchemaNodeUtils.getRpcDataSchema(rpc, qname);
Preconditions.checkArgument(schema != null, "Schema for %s does not define input / output.", rpc.getQName());
- return (ContainerNodeCodecContext) DataContainerCodecPrototype.from(key, schema, factory()).get();
+ return (ContainerNodeCodecContext<?>) DataContainerCodecPrototype.from(key, schema, factory()).get();
}
- private NotificationCodecContext createNotificationDataContext(final Class<?> notificationType) {
+ private NotificationCodecContext<?> createNotificationDataContext(final Class<?> notificationType) {
Preconditions.checkArgument(Notification.class.isAssignableFrom(notificationType));
Preconditions.checkArgument(notificationType.isInterface(), "Supplied class must be interface.");
final QName qname = BindingReflections.findQName(notificationType);
SchemaPath.create(true, qname));
Preconditions.checkArgument(schema != null, "Supplied %s is not valid notification", notificationType);
- return new NotificationCodecContext(notificationType, schema, factory());
+ return new NotificationCodecContext<>(notificationType, schema, factory());
+ }
+
+ @Override
+ protected Object deserializeObject(final NormalizedNode<?, ?> normalizedNode) {
+ throw new UnsupportedOperationException("Unable to deserialize root");
+ }
+
+ @Override
+ public InstanceIdentifier.PathArgument deserializePathArgument(final YangInstanceIdentifier.PathArgument arg) {
+ Preconditions.checkArgument(arg == null);
+ return null;
+ }
+
+ @Override
+ public YangInstanceIdentifier.PathArgument serializePathArgument(final InstanceIdentifier.PathArgument arg) {
+ Preconditions.checkArgument(arg == null);
+ return null;
+ }
+
+ private static <K,V> V getOrRethrow(final LoadingCache<K, V> cache, final K key) {
+ try {
+ return cache.getUnchecked(key);
+ } catch (final UncheckedExecutionException e) {
+ final Throwable cause = e.getCause();
+ if(cause != null) {
+ Throwables.propagateIfPossible(cause);
+ }
+ throw e;
+ }
}
}
\ No newline at end of file