2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.sal.connect.netconf.util;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkNotNull;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.FluentIterable;
16 import com.google.common.collect.ImmutableMap;
17 import com.google.common.collect.ImmutableSet;
18 import com.google.common.collect.Iterables;
19 import com.google.common.collect.Lists;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
26 import java.util.Map.Entry;
28 import java.util.concurrent.ConcurrentHashMap;
29 import javax.xml.transform.dom.DOMSource;
30 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
31 import org.opendaylight.yangtools.concepts.Identifiable;
32 import org.opendaylight.yangtools.yang.common.QName;
33 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
40 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
45 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
46 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
47 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
48 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
49 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
50 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
52 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
53 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
54 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
55 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
56 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
57 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
58 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
59 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
60 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
61 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
64 * Transforms an instance of yang instance identifier to a filter like structure in normalized node format. Can be also used to nest the edit-config rpc content.
65 * For each argument of the id, a specific normalized node is created to ensure schema context conformance.
67 public abstract class InstanceIdToNodes<T extends PathArgument> implements Identifiable<T> {
69 private final T identifier;
72 public T getIdentifier() {
76 protected InstanceIdToNodes(final T identifier) {
77 this.identifier = identifier;
80 abstract InstanceIdToNodes<?> getChild(final PathArgument child) throws DataNormalizationException;
82 public abstract NormalizedNode<?, ?> create(YangInstanceIdentifier legacyData, Optional<NormalizedNode<?, ?>> deepestChild, Optional<ModifyAction> operation);
84 private static abstract class SimpleTypeNormalization<T extends PathArgument> extends InstanceIdToNodes<T> {
86 protected SimpleTypeNormalization(final T identifier) {
91 public NormalizedNode<?, ?> create(final YangInstanceIdentifier id, final Optional<NormalizedNode<?, ?>> deepestChild, final Optional<ModifyAction> operation) {
93 final PathArgument pathArgument = Iterables.get(id.getPathArguments(), 0);
94 final NormalizedNodeAttrBuilder<? extends PathArgument, Object, ? extends NormalizedNode<? extends PathArgument, Object>> builder = getBuilder(pathArgument);
96 if(deepestChild.isPresent()) {
97 builder.withValue(deepestChild.get().getValue());
100 addModifyOpIfPresent(operation, builder);
101 return builder.build();
104 protected abstract NormalizedNodeAttrBuilder<? extends PathArgument, Object, ? extends NormalizedNode<? extends PathArgument, Object>> getBuilder(PathArgument node);
107 public InstanceIdToNodes<?> getChild(final PathArgument child) {
113 public void addModifyOpIfPresent(final Optional<ModifyAction> operation, final AttributesBuilder<?> builder) {
114 if(operation.isPresent()) {
115 builder.withAttributes(Collections.singletonMap(NetconfMessageTransformUtil.NETCONF_OPERATION_QNAME, NetconfMessageTransformUtil.modifyOperationToXmlString(operation.get())));
119 private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
121 protected LeafNormalization(final LeafSchemaNode potential) {
122 super(new NodeIdentifier(potential.getQName()));
126 protected NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> getBuilder(final PathArgument node) {
127 return Builders.leafBuilder().withNodeIdentifier(getIdentifier());
131 private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
133 public LeafListEntryNormalization(final LeafListSchemaNode potential) {
134 super(new NodeWithValue(potential.getQName(), null));
138 protected NormalizedNodeAttrBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> getBuilder(final PathArgument node) {
139 Preconditions.checkArgument(node instanceof NodeWithValue);
140 return Builders.leafSetEntryBuilder().withNodeIdentifier((NodeWithValue) node).withValue(((NodeWithValue) node).getValue());
145 private static abstract class CompositeNodeNormalizationOperation<T extends PathArgument> extends
146 InstanceIdToNodes<T> {
148 protected CompositeNodeNormalizationOperation(final T identifier) {
153 @SuppressWarnings("unchecked")
154 public final NormalizedNode<?, ?> create(final YangInstanceIdentifier id, final Optional<NormalizedNode<?, ?>> lastChild, final Optional<ModifyAction> operation) {
156 final Iterator<PathArgument> iterator = id.getPathArguments().iterator();
157 final PathArgument legacyData = iterator.next();
159 if (!isMixin(this) && getIdentifier().getNodeType() != null) {
160 checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()),
161 "Node QName must be %s was %s", getIdentifier().getNodeType(), legacyData.getNodeType());
163 final NormalizedNodeContainerBuilder builder = createBuilder(legacyData);
165 if (iterator.hasNext()) {
166 final PathArgument childPath = iterator.next();
167 final InstanceIdToNodes childOp = getChildOperation(childPath);
169 final YangInstanceIdentifier childId = YangInstanceIdentifier.create(Iterables.skip(id.getPathArguments(), 1));
170 builder.addChild(childOp.create(childId, lastChild, operation));
172 if(lastChild.isPresent()) {
173 builder.withValue(Lists.newArrayList((Collection<?>) lastChild.get().getValue()));
175 if(operation.isPresent()) {
176 Preconditions.checkArgument(builder instanceof AttributesBuilder<?>);
177 addModifyOpIfPresent(operation, ((AttributesBuilder<?>) builder));
181 return builder.build();
184 private InstanceIdToNodes getChildOperation(final PathArgument childPath) {
185 final InstanceIdToNodes childOp;
187 childOp = getChild(childPath);
188 } catch (final DataNormalizationException e) {
189 throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
191 checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
195 @SuppressWarnings("rawtypes")
196 protected abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode);
199 static boolean isMixin(final InstanceIdToNodes<?> op) {
200 return op instanceof MixinNormalizationOp;
203 private static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
204 CompositeNodeNormalizationOperation<T> {
206 private final DataNodeContainer schema;
207 private final Map<PathArgument, InstanceIdToNodes<?>> byArg;
209 protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
211 this.schema = schema;
212 this.byArg = new ConcurrentHashMap<>();
216 public InstanceIdToNodes<?> getChild(final PathArgument child) throws DataNormalizationException {
217 InstanceIdToNodes<?> potential = byArg.get(child);
218 if (potential != null) {
221 potential = fromLocalSchema(child);
222 return register(potential);
225 private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) throws DataNormalizationException {
226 if (child instanceof AugmentationIdentifier) {
227 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
230 return fromSchemaAndQNameChecked(schema, child.getNodeType());
233 private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
234 if (potential != null) {
235 byArg.put(potential.getIdentifier(), potential);
241 private static final class ListItemNormalization extends
242 DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
244 protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
245 super(identifier, schema);
249 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument currentArg) {
250 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
251 .mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates) currentArg);
252 for (final Entry<QName, Object> keyValue : ((NodeIdentifierWithPredicates) currentArg).getKeyValues().entrySet()) {
253 builder.addChild(Builders.leafBuilder()
255 .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue())
263 private static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
265 protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
266 super(new NodeIdentifier(schema.getQName()), schema);
270 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
271 return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
276 private static final class ContainerTransformation extends DataContainerNormalizationOperation<NodeIdentifier> {
278 protected ContainerTransformation(final ContainerSchemaNode schema) {
279 super(new NodeIdentifier(schema.getQName()), schema);
283 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
284 return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
289 * Marker interface for Mixin nodes normalization operations
291 private interface MixinNormalizationOp {}
294 private static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
297 public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
302 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
303 return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
307 private static class UnorderedLeafListMixinNormalization extends CompositeNodeNormalizationOperation<NodeIdentifier> implements MixinNormalizationOp {
309 private final InstanceIdToNodes<?> innerOp;
311 public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
312 super(new NodeIdentifier(potential.getQName()));
313 innerOp = new LeafListEntryNormalization(potential);
317 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
318 return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
322 public InstanceIdToNodes<?> getChild(final PathArgument child) {
323 if (child instanceof NodeWithValue) {
330 private static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> implements MixinNormalizationOp {
332 public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
334 super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation, schema));
338 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
339 return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
343 private static class UnorderedMapMixinNormalization extends CompositeNodeNormalizationOperation<NodeIdentifier> implements MixinNormalizationOp {
345 private final ListItemNormalization innerNode;
347 public UnorderedMapMixinNormalization(final ListSchemaNode list) {
348 super(new NodeIdentifier(list.getQName()));
349 this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
350 Collections.<QName, Object>emptyMap()), list);
354 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
355 return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
359 public InstanceIdToNodes<?> getChild(final PathArgument child) {
360 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
367 private static class UnkeyedListMixinNormalization extends CompositeNodeNormalizationOperation<NodeIdentifier> implements MixinNormalizationOp {
369 private final UnkeyedListItemNormalization innerNode;
371 public UnkeyedListMixinNormalization(final ListSchemaNode list) {
372 super(new NodeIdentifier(list.getQName()));
373 this.innerNode = new UnkeyedListItemNormalization(list);
377 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
378 return Builders.unkeyedListBuilder().withNodeIdentifier(getIdentifier());
382 public InstanceIdToNodes<?> getChild(final PathArgument child) {
383 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
391 private static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
393 public OrderedMapMixinNormalization(final ListSchemaNode list) {
398 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
399 return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
404 private static class ChoiceNodeNormalization extends CompositeNodeNormalizationOperation<NodeIdentifier> implements MixinNormalizationOp {
406 private final ImmutableMap<PathArgument, InstanceIdToNodes<?>> byArg;
408 protected ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
409 super(new NodeIdentifier(schema.getQName()));
410 final ImmutableMap.Builder<PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
412 for (final ChoiceCaseNode caze : schema.getCases()) {
413 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
414 final InstanceIdToNodes<?> childOp = fromDataSchemaNode(cazeChild);
415 byArgBuilder.put(childOp.getIdentifier(), childOp);
418 byArg = byArgBuilder.build();
422 public InstanceIdToNodes<?> getChild(final PathArgument child) {
423 return byArg.get(child);
427 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
428 return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
432 private static class AnyXmlNormalization extends InstanceIdToNodes<NodeIdentifier> {
434 protected AnyXmlNormalization(final AnyXmlSchemaNode schema) {
435 super(new NodeIdentifier(schema.getQName()));
439 public InstanceIdToNodes<?> getChild(final PathArgument child) throws DataNormalizationException {
444 public NormalizedNode<?, ?> create(final YangInstanceIdentifier legacyData, final Optional<NormalizedNode<?, ?>> deepestChild, final Optional<ModifyAction> operation) {
445 if(deepestChild.isPresent()) {
446 Preconditions.checkState(deepestChild instanceof AnyXmlNode);
447 final NormalizedNodeAttrBuilder<NodeIdentifier, DOMSource, AnyXmlNode> anyXmlBuilder =
448 Builders.anyXmlBuilder().withNodeIdentifier(getIdentifier()).withValue(((AnyXmlNode) deepestChild).getValue());
449 addModifyOpIfPresent(operation, anyXmlBuilder);
450 return anyXmlBuilder.build();
453 final NormalizedNodeAttrBuilder<NodeIdentifier, DOMSource, AnyXmlNode> builder =
454 Builders.anyXmlBuilder().withNodeIdentifier(getIdentifier());
455 addModifyOpIfPresent(operation, builder);
456 return builder.build();
461 private static Optional<DataSchemaNode> findChildSchemaNode(final DataNodeContainer parent, final QName child) {
462 DataSchemaNode potential = parent.getDataChildByName(child);
463 if (potential == null) {
464 final Iterable<ChoiceSchemaNode> choices = FluentIterable.from(parent.getChildNodes()).filter(ChoiceSchemaNode.class);
465 potential = findChoice(choices, child);
467 return Optional.fromNullable(potential);
470 private static InstanceIdToNodes<?> fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) throws DataNormalizationException {
471 final Optional<DataSchemaNode> potential = findChildSchemaNode(schema, child);
472 if (!potential.isPresent()) {
473 throw new DataNormalizationException(String.format("Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child, schema, schema.getChildNodes()));
476 final DataSchemaNode result = potential.get();
477 // We try to look up if this node was added by augmentation
478 if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
479 return fromAugmentation(schema, (AugmentationTarget) schema, result);
481 return fromDataSchemaNode(result);
484 private static ChoiceSchemaNode findChoice(final Iterable<ChoiceSchemaNode> choices, final QName child) {
485 org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode foundChoice = null;
487 for (final ChoiceSchemaNode choice : choices) {
488 for (final ChoiceCaseNode caze : choice.getCases()) {
489 if (findChildSchemaNode(caze, child).isPresent()) {
490 foundChoice = choice;
498 private static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
499 final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
500 for (final DataSchemaNode child : augmentation.getChildNodes()) {
501 potentialChildren.add(child.getQName());
503 return new AugmentationIdentifier(potentialChildren.build());
506 private static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation, final DataNodeContainer schema) {
507 final Set<DataSchemaNode> children = new HashSet<>();
508 for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
509 children.add(schema.getDataChildByName(augNode.getQName()));
511 return new NodeContainerProxy(null, children);
515 * Returns a SchemaPathUtil for provided child node
517 * If supplied child is added by Augmentation this operation returns
518 * a SchemaPathUtil for augmentation,
519 * otherwise returns a SchemaPathUtil for child as
520 * call for {@link #fromDataSchemaNode(org.opendaylight.yangtools.yang.model.api.DataSchemaNode)}.
522 private static InstanceIdToNodes<?> fromAugmentation(final DataNodeContainer parent,
523 final AugmentationTarget parentAug, final DataSchemaNode child) {
524 AugmentationSchema augmentation = null;
525 for (final AugmentationSchema aug : parentAug.getAvailableAugmentations()) {
526 final DataSchemaNode potential = aug.getDataChildByName(child.getQName());
527 if (potential != null) {
533 if (augmentation != null) {
534 return new AugmentationNormalization(augmentation, parent);
536 return fromDataSchemaNode(child);
540 private static InstanceIdToNodes<?> fromDataSchemaNode(final DataSchemaNode potential) {
541 if (potential instanceof ContainerSchemaNode) {
542 return new ContainerTransformation((ContainerSchemaNode) potential);
543 } else if (potential instanceof ListSchemaNode) {
544 return fromListSchemaNode((ListSchemaNode) potential);
545 } else if (potential instanceof LeafSchemaNode) {
546 return new LeafNormalization((LeafSchemaNode) potential);
547 } else if (potential instanceof ChoiceSchemaNode) {
548 return new ChoiceNodeNormalization((ChoiceSchemaNode) potential);
549 } else if (potential instanceof LeafListSchemaNode) {
550 return fromLeafListSchemaNode((LeafListSchemaNode) potential);
551 } else if (potential instanceof AnyXmlSchemaNode) {
552 return new AnyXmlNormalization((AnyXmlSchemaNode) potential);
557 private static InstanceIdToNodes<?> fromListSchemaNode(final ListSchemaNode potential) {
558 final List<QName> keyDefinition = potential.getKeyDefinition();
559 if (keyDefinition == null || keyDefinition.isEmpty()) {
560 return new UnkeyedListMixinNormalization(potential);
562 if (potential.isUserOrdered()) {
563 return new OrderedMapMixinNormalization(potential);
565 return new UnorderedMapMixinNormalization(potential);
568 private static InstanceIdToNodes<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) {
569 if (potential.isUserOrdered()) {
570 return new OrderedLeafListMixinNormalization(potential);
572 return new UnorderedLeafListMixinNormalization(potential);
575 public static NormalizedNode<?, ?> serialize(final SchemaContext ctx, final YangInstanceIdentifier id) {
576 return serialize(ctx, id, Optional.<NormalizedNode<?, ?>>absent(), Optional.<ModifyAction>absent());
579 public static NormalizedNode<?, ?> serialize(final SchemaContext ctx, final YangInstanceIdentifier id, final NormalizedNode<?, ?> deepestElement) {
580 return serialize(ctx, id, Optional.<NormalizedNode<?, ?>>of(deepestElement), Optional.<ModifyAction>absent());
583 public static NormalizedNode<?, ?> serialize(final SchemaContext ctx, final YangInstanceIdentifier id, final Optional<NormalizedNode<?, ?>> deepestElement, final Optional<ModifyAction> operation) {
584 Preconditions.checkNotNull(ctx);
585 Preconditions.checkNotNull(id);
586 final PathArgument topLevelElement = id.getPathArguments().iterator().next();
587 final DataSchemaNode dataChildByName = ctx.getDataChildByName(topLevelElement.getNodeType());
588 Preconditions.checkNotNull(dataChildByName, "Cannot find %s node in schema context. Instance identifier has to start from root", topLevelElement);
590 final InstanceIdToNodes<?> instanceIdToNodes = fromSchemaAndQNameChecked(ctx, topLevelElement.getNodeType());
591 return instanceIdToNodes.create(id, deepestElement, operation);
592 } catch (final DataNormalizationException e) {
593 throw new IllegalArgumentException("Unable to serialize: " + id, e);