/* * JBoss, Home of Professional Open Source. * Copyright 2016, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.cli.operation.impl; import java.util.List; import org.jboss.as.cli.CommandContext; import org.jboss.as.cli.CommandFormatException; import org.jboss.as.cli.CommandLineCompleter; import org.jboss.as.cli.Util; import org.jboss.as.cli.operation.ParsedOperationRequestHeader; /** * * @author Alexey Loubyansky */ public class RolloutPlanCompleter implements CommandLineCompleter { public static final RolloutPlanCompleter INSTANCE = new RolloutPlanCompleter(); private static final DefaultOperationRequestAddress address = new DefaultOperationRequestAddress(); static { address.toNode(Util.MANAGEMENT_CLIENT_CONTENT, Util.ROLLOUT_PLANS); } private final DefaultCallbackHandler parsedOp = new DefaultCallbackHandler(); /* (non-Javadoc) * @see org.jboss.as.cli.CommandLineCompleter#complete(org.jboss.as.cli.CommandContext, java.lang.String, int, java.util.List) */ @Override public int complete(CommandContext ctx, String buffer, int cursor, List<String> candidates) { if(!ctx.isDomainMode()) { return -1; } if(buffer.isEmpty()) { candidates.add("{rollout"); return 0; } try { parsedOp.parseOperation(null, buffer); } catch (CommandFormatException e) { return -1; } if(parsedOp.isRequestComplete()) { return -1; } if(parsedOp.endsOnHeaderListStart() || parsedOp.endsOnHeaderSeparator()) { candidates.add("rollout"); return parsedOp.getLastSeparatorIndex() + 1; } if(parsedOp.getLastHeader() == null) { if(ctx.getParsedCommandLine().getOriginalLine().endsWith(" ") /* '{rollout ' */) { final String originalLine = ctx.getParsedCommandLine().getOriginalLine(); int bufferIndex = originalLine.lastIndexOf(buffer); if(bufferIndex == -1) { // that's illegal state return -1; } candidates.add("name="); candidates.addAll(Util.getServerGroups(ctx.getModelControllerClient())); return originalLine.length() - bufferIndex; } else if (ctx.getParsedCommandLine().getOriginalLine().endsWith("rollout")) { // In order to have the completion to be allowed to continue candidates.add(" "); } return buffer.length(); } final ParsedOperationRequestHeader lastHeader = parsedOp.getLastHeader(); if(!(lastHeader instanceof ParsedRolloutPlanHeader)) { throw new IllegalStateException("Expected " + ParsedRolloutPlanHeader.class + " but got " + lastHeader.getName() + " of " + lastHeader); } final ParsedRolloutPlanHeader rollout = (ParsedRolloutPlanHeader) lastHeader; if(rollout.endsOnPlanIdValueSeparator()) { candidates.addAll(Util.getNodeNames(ctx.getModelControllerClient(), address, Util.ROLLOUT_PLAN)); return rollout.getLastSeparatorIndex() + 1; } final String planRef = rollout.getPlanRef(); if(planRef != null) { final List<String> nodeNames = Util.getNodeNames(ctx.getModelControllerClient(), address, Util.ROLLOUT_PLAN); for(String name : nodeNames) { if(name.startsWith(planRef)) { candidates.add(name); } } return rollout.getLastChunkIndex(); } if(rollout.hasProperties()) { final String lastName = rollout.getLastPropertyName(); if(Util.ROLLBACK_ACROSS_GROUPS.startsWith(lastName)) { candidates.add(Util.ROLLBACK_ACROSS_GROUPS); } return rollout.getLastChunkIndex(); } if(rollout.endsOnGroupSeparator()) { final List<String> serverGroups = Util.getServerGroups(ctx.getModelControllerClient()); for(String group : serverGroups) { if(!rollout.containsGroup(group)) { candidates.add(group); } } return buffer.length(); } final SingleRolloutPlanGroup lastGroup = rollout.getLastGroup(); if(lastGroup == null) { return -1; } if(lastGroup.endsOnPropertyListEnd()) { candidates.add("^"); candidates.add(","); if(Character.isWhitespace(buffer.charAt(buffer.length() - 1))) { // header properties candidates.add(Util.ROLLBACK_ACROSS_GROUPS); } candidates.add(";"); candidates.add("}"); return buffer.length(); } if(lastGroup.endsOnPropertyListStart()) { candidates.add(Util.MAX_FAILED_SERVERS); candidates.add(Util.MAX_FAILURE_PERCENTAGE); candidates.add(Util.ROLLING_TO_SERVERS); candidates.add(Util.NOT_OPERATOR); return buffer.length(); } // Only return the set of boolean properties if (lastGroup.endsOnNotOperator()) { candidates.add(Util.ROLLING_TO_SERVERS); return buffer.length(); } if (lastGroup.hasProperties()) { // To propose the right end character boolean containsAll = lastGroup.hasProperty(Util.MAX_FAILED_SERVERS) && lastGroup.hasProperty(Util.MAX_FAILURE_PERCENTAGE) && lastGroup.hasProperty(Util.ROLLING_TO_SERVERS); final String propValue = lastGroup.getLastPropertyValue(); if(propValue != null) { if(Util.TRUE.startsWith(propValue)) { candidates.add(Util.TRUE); } else if(Util.FALSE.startsWith(propValue)) { candidates.add(Util.FALSE); } else { candidates.add(containsAll ? ")" : ","); return buffer.length(); } } else if(lastGroup.endsOnPropertyValueSeparator()) { if(Util.ROLLING_TO_SERVERS.equals(lastGroup.getLastPropertyName())) { candidates.add(Util.FALSE); candidates.add(containsAll ? ")" : ","); } return buffer.length(); } else if(lastGroup.endsOnPropertySeparator()) { if(!lastGroup.hasProperty(Util.MAX_FAILED_SERVERS)) { candidates.add(Util.MAX_FAILED_SERVERS); } if(!lastGroup.hasProperty(Util.MAX_FAILURE_PERCENTAGE)) { candidates.add(Util.MAX_FAILURE_PERCENTAGE); } if(!lastGroup.hasProperty(Util.ROLLING_TO_SERVERS)) { candidates.add(Util.ROLLING_TO_SERVERS); candidates.add(Util.NOT_OPERATOR); } return lastGroup.getLastSeparatorIndex() + 1; } else { final String propName = lastGroup.getLastPropertyName(); if(Util.MAX_FAILED_SERVERS.startsWith(propName)) { candidates.add(Util.MAX_FAILED_SERVERS + '='); } if(Util.MAX_FAILURE_PERCENTAGE.startsWith(propName)) { candidates.add(Util.MAX_FAILURE_PERCENTAGE + '='); } else if (Util.ROLLING_TO_SERVERS.equals(propName)) { if (lastGroup.isLastPropertyNegated() && !containsAll) { candidates.add(Util.ROLLING_TO_SERVERS + ","); } else { candidates.add("=" + Util.FALSE); if (!containsAll) { candidates.add(","); } else { candidates.add(")"); } } } else if (Util.ROLLING_TO_SERVERS.startsWith(propName)) { candidates.add(Util.ROLLING_TO_SERVERS); } } if (candidates.isEmpty() && containsAll) { candidates.add(")"); } return lastGroup.getLastChunkIndex(); } if(Character.isWhitespace(buffer.charAt(buffer.length() - 1))) { candidates.add("("); candidates.add("^"); candidates.add(","); // header propersties candidates.add(Util.ROLLBACK_ACROSS_GROUPS); candidates.add(";"); candidates.add("}"); return buffer.length(); } int result = lastGroup.getLastChunkIndex(); final String groupName = lastGroup.getGroupName(); final List<String> serverGroups = Util.getServerGroups(ctx.getModelControllerClient()); for(String group : serverGroups) { if(group.startsWith(groupName)) { candidates.add(group); } } if(Util.NAME.startsWith(groupName)) { candidates.add("name="); } else { if (candidates.size() == 1) { final String group = candidates.get(0); candidates.set(0, group + '('); candidates.add(group + ','); candidates.add(group + '^'); candidates.add(group + ';'); candidates.add(group + '}'); } } return result; } }