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