Merge "BUG 2799: SPI for EventSources"
[controller.git] / opendaylight / netconf / netconf-cli / src / main / java / org / opendaylight / controller / netconf / cli / reader / impl / ChoiceReader.java
1 /*
2  * Copyright (c) 2014 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 package org.opendaylight.controller.netconf.cli.reader.impl;
9
10 import static org.opendaylight.controller.netconf.cli.io.IOUtil.isSkipInput;
11
12 import com.google.common.base.Function;
13 import com.google.common.collect.Maps;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import jline.console.completer.Completer;
22 import jline.console.completer.StringsCompleter;
23 import org.opendaylight.controller.netconf.cli.CommandArgHandlerRegistry;
24 import org.opendaylight.controller.netconf.cli.io.BaseConsoleContext;
25 import org.opendaylight.controller.netconf.cli.io.ConsoleContext;
26 import org.opendaylight.controller.netconf.cli.io.ConsoleIO;
27 import org.opendaylight.controller.netconf.cli.reader.AbstractReader;
28 import org.opendaylight.controller.netconf.cli.reader.ReadingException;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
31 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
33 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
34 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
38 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 public class ChoiceReader extends AbstractReader<ChoiceSchemaNode> {
43
44     private static final Logger LOG = LoggerFactory.getLogger(ChoiceReader.class);
45
46     private final CommandArgHandlerRegistry argumentHandlerRegistry;
47
48     public ChoiceReader(final ConsoleIO console, final CommandArgHandlerRegistry argumentHandlerRegistry,
49             final SchemaContext schemaContext) {
50         super(console, schemaContext);
51         this.argumentHandlerRegistry = argumentHandlerRegistry;
52     }
53
54     public ChoiceReader(final ConsoleIO console, final CommandArgHandlerRegistry argumentHandlerRegistry,
55             final SchemaContext schemaContext, final boolean readConfigNode) {
56         super(console, schemaContext, readConfigNode);
57         this.argumentHandlerRegistry = argumentHandlerRegistry;
58     }
59
60     @Override
61     public List<NormalizedNode<?, ?>> readWithContext(final ChoiceSchemaNode choiceNode) throws IOException, ReadingException {
62         final Map<String, ChoiceCaseNode> availableCases = collectAllCases(choiceNode);
63         console.formatLn("Select case for choice %s from: %s", choiceNode.getQName().getLocalName(),
64                 formatSet(availableCases.keySet()));
65
66         ChoiceCaseNode selectedCase = null;
67         final String rawValue = console.read();
68         if (isSkipInput(rawValue)) {
69             return Collections.emptyList();
70         }
71
72         selectedCase = availableCases.get(rawValue);
73         if (selectedCase == null) {
74             final String message = String.format("Incorrect value (%s) for choice %s was selected.", rawValue,
75                     choiceNode.getQName().getLocalName());
76             LOG.error(message);
77             throw new ReadingException(message);
78         }
79
80         return Collections.<NormalizedNode<?, ?>>singletonList(
81                 ImmutableChoiceNodeBuilder.create()
82                         .withNodeIdentifier(new NodeIdentifier(choiceNode.getQName()))
83                         .withValue(((Collection) readSelectedCase(selectedCase))).build());
84     }
85
86     protected List<NormalizedNode<?, ?>> readSelectedCase(final ChoiceCaseNode selectedCase) throws ReadingException {
87         // IF there is a case that contains only one Empty type leaf, create the
88         // leaf without question, since the case was selected
89         if (containsOnlyOneEmptyLeaf(selectedCase)) {
90             final NormalizedNode<?, ?> newNode = ImmutableLeafNodeBuilder.create()
91                     .withNodeIdentifier(new NodeIdentifier(selectedCase.getChildNodes().iterator().next().getQName())).build();
92             return Collections.<NormalizedNode<?, ?>>singletonList(newNode);
93         }
94
95         final List<NormalizedNode<?, ?>> newNodes = new ArrayList<>();
96         for (final DataSchemaNode schemaNode : selectedCase.getChildNodes()) {
97             newNodes.addAll(argumentHandlerRegistry.getGenericReader(getSchemaContext(), getReadConfigNode()).read(
98                     schemaNode));
99         }
100         return newNodes;
101     }
102
103     private Object formatSet(final Set<String> values) {
104         final StringBuilder formatedValues = new StringBuilder();
105         for (final String value : values) {
106             formatedValues.append("\n  ");
107             formatedValues.append(value);
108         }
109         return formatedValues.toString();
110     }
111
112     private boolean containsOnlyOneEmptyLeaf(final ChoiceCaseNode selectedCase) {
113         if (selectedCase.getChildNodes().size() != 1) {
114             return false;
115         }
116         final DataSchemaNode next = selectedCase.getChildNodes().iterator().next();
117         if (next instanceof LeafSchemaNode) {
118             final TypeDefinition<?> type = ((LeafSchemaNode) next).getType();
119             if (isEmptyType(type)) {
120                 return true;
121             }
122         }
123         return false;
124     }
125
126     private Map<String, ChoiceCaseNode> collectAllCases(final ChoiceSchemaNode schemaNode) {
127         return Maps.uniqueIndex(schemaNode.getCases(), new Function<ChoiceCaseNode, String>() {
128             @Override
129             public String apply(final ChoiceCaseNode input) {
130                 return input.getQName().getLocalName();
131             }
132         });
133     }
134
135     @Override
136     protected ConsoleContext getContext(final ChoiceSchemaNode schemaNode) {
137         return new BaseConsoleContext<ChoiceSchemaNode>(schemaNode) {
138             @Override
139             public List<Completer> getAdditionalCompleters() {
140                 return Collections
141                         .<Completer> singletonList(new StringsCompleter(collectAllCases(schemaNode).keySet()));
142             }
143         };
144     }
145 }