org.apache.geode.management.internal.cli.CliUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.geode.management.internal.cli.CliUtil.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.apache.geode.management.internal.cli;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import org.apache.commons.lang.StringUtils;

import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.execute.AbstractExecution;
import org.apache.geode.internal.cache.tier.sockets.CacheClientProxy;
import org.apache.geode.internal.util.IOUtils;
import org.apache.geode.management.DistributedSystemMXBean;
import org.apache.geode.management.ManagementService;
import org.apache.geode.management.cli.Result;
import org.apache.geode.management.internal.cli.functions.MembersForRegionFunction;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.shell.Gfsh;

/**
 * This class contains utility methods used by classes used to build the Command Line Interface
 * (CLI).
 *
 * @since GemFire 7.0
 */
public class CliUtil {
    public static final FileFilter JAR_FILE_FILTER = new CustomFileFilter(".jar");

    public static String cliDependenciesExist(boolean includeGfshDependencies) {
        String jarProductName;

        // Parser & CliCommand from Spring Shell
        jarProductName = checkLibraryByLoadingClass("org.springframework.shell.core.Parser", "Spring Shell");
        jarProductName = checkLibraryByLoadingClass("org.springframework.shell.core.annotation.CliCommand",
                "Spring Shell");
        if (jarProductName != null) {
            return jarProductName;
        }

        // SpringVersion from Spring Core
        jarProductName = checkLibraryByLoadingClass("org.springframework.core.SpringVersion", "Spring Core");
        if (jarProductName != null) {
            return jarProductName;
        }

        if (includeGfshDependencies) {
            // ConsoleReader from jline
            jarProductName = checkLibraryByLoadingClass("jline.console.ConsoleReader", "JLine");
            if (jarProductName != null) {
                return jarProductName;
            }
        }

        return jarProductName;
    }

    private static String checkLibraryByLoadingClass(String className, String jarProductName) {
        try {
            ClassPathLoader.getLatest().forName(className);
        } catch (ClassNotFoundException e) {
            return jarProductName;
        }

        return null;
    }

    public static InternalCache getCacheIfExists() {
        InternalCache cache;
        try {
            cache = getInternalCache();
        } catch (CacheClosedException e) {
            // ignore & return null
            cache = null;
        }

        return cache;
    }

    public static byte[][] filesToBytes(String[] fileNames) throws IOException {
        List<byte[]> filesDataList = new ArrayList<>();

        for (String fileName : fileNames) {
            File file = new File(fileName);

            if (!file.exists()) {
                throw new FileNotFoundException("Could not find " + file.getCanonicalPath());
            }

            if (file.isDirectory()) {
                File[] childrenFiles = file.listFiles(JAR_FILE_FILTER);
                for (File childrenFile : childrenFiles) {
                    // 1. add name of the file as bytes at even index
                    filesDataList.add(childrenFile.getName().getBytes());
                    // 2. add file contents as bytes at odd index
                    filesDataList.add(toByteArray(new FileInputStream(childrenFile)));
                }
            } else {
                filesDataList.add(file.getName().getBytes());
                filesDataList.add(toByteArray(new FileInputStream(file)));
            }
        }

        byte[][] filesData = new byte[filesDataList.size()][];

        filesData = filesDataList.toArray(filesData);

        return filesData;
    }

    public static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        int n = 0;
        byte[] buffer = new byte[4096];
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }

        return output.toByteArray();
    }

    public static String[] bytesToNames(byte[][] fileData) {
        String[] names = new String[fileData.length / 2];
        for (int i = 0; i < fileData.length; i += 2) {
            names[i / 2] = new String(fileData[i]);
        }

        return names;
    }

    public static byte[][] bytesToData(byte[][] fileData) {
        byte[][] data = new byte[fileData.length / 2][];
        for (int i = 1; i < fileData.length; i += 2) {
            data[i / 2] = fileData[i];
        }

        return data;
    }

    public static void bytesToFiles(byte[][] fileData, String parentDirPath, boolean mkRequireddirs)
            throws IOException, UnsupportedOperationException {
        FileOutputStream fos = null;

        File parentDir = new File(parentDirPath);
        if (mkRequireddirs && !parentDir.exists()) {
            if (!parentDir.mkdirs()) {
                throw new UnsupportedOperationException(
                        "Couldn't create required directory structure for " + parentDirPath);
            }
        }
        for (int i = 0; i < fileData.length; i++) {
            if (i % 2 == 0) {
                // Expect file name as bytes at even index
                String fileName = new String(fileData[i]);
                fos = new FileOutputStream(new File(parentDir, fileName));
            } else {
                // Expect file contents as bytes at odd index
                fos.write(fileData[i]);
                fos.close();
            }
        }
    }

    private static InternalCache getInternalCache() {
        return (InternalCache) CacheFactory.getAnyInstance();
    }

    public static Set<String> getAllRegionNames() {
        InternalCache cache = getInternalCache();
        Set<String> regionNames = new HashSet<>();
        Set<Region<?, ?>> rootRegions = cache.rootRegions();

        for (Region<?, ?> rootRegion : rootRegions) {
            regionNames.add(rootRegion.getFullPath().substring(1));

            Set<Region<?, ?>> subRegions = rootRegion.subregions(true);

            for (Region<?, ?> subRegion : subRegions) {
                regionNames.add(subRegion.getFullPath().substring(1));
            }
        }
        return regionNames;
    }

    public static String convertStringSetToString(Set<String> stringSet, char delimiter) {
        StringBuilder sb = new StringBuilder();
        if (stringSet != null) {

            for (String stringValue : stringSet) {
                sb.append(stringValue);
                sb.append(delimiter);
            }
        }
        return sb.toString();
    }

    public static String convertStringListToString(List<String> stringList, char delimiter) {
        StringBuilder sb = new StringBuilder();
        if (stringList != null) {

            for (String stringValue : stringList) {
                sb.append(stringValue);
                sb.append(delimiter);
            }
        }
        return sb.toString();
    }

    /**
     * Finds all Members (including both servers and locators) which belong to the given arrays of
     * groups or members.
     */
    public static Set<DistributedMember> findMembersIncludingLocators(String[] groups, String[] members) {
        InternalCache cache = getInternalCache();
        Set<DistributedMember> allMembers = getAllMembers(cache);

        return findMembers(allMembers, groups, members);
    }

    /**
     * Finds all Servers which belong to the given arrays of groups or members. Does not include
     * locators.
     */
    public static Set<DistributedMember> findMembers(String[] groups, String[] members) {
        InternalCache cache = getInternalCache();
        Set<DistributedMember> allNormalMembers = getAllNormalMembers(cache);

        return findMembers(allNormalMembers, groups, members);
    }

    private static Set<DistributedMember> findMembers(Set<DistributedMember> membersToConsider, String[] groups,
            String[] members) {
        if (groups == null) {
            groups = new String[] {};
        }

        if (members == null) {
            members = new String[] {};
        }

        if ((members.length > 0) && (groups.length > 0)) {
            throw new IllegalArgumentException(CliStrings.PROVIDE_EITHER_MEMBER_OR_GROUP_MESSAGE);
        }

        if (members.length == 0 && groups.length == 0) {
            return membersToConsider;
        }

        Set<DistributedMember> matchingMembers = new HashSet<>();
        // it will either go into this loop or the following loop, not both.
        for (String memberNameOrId : members) {
            for (DistributedMember member : membersToConsider) {
                if (memberNameOrId.equalsIgnoreCase(member.getId()) || memberNameOrId.equals(member.getName())) {
                    matchingMembers.add(member);
                }
            }
        }

        for (String group : groups) {
            for (DistributedMember member : membersToConsider) {
                if (member.getGroups().contains(group)) {
                    matchingMembers.add(member);
                }
            }
        }
        return matchingMembers;
    }

    public static DistributedMember getDistributedMemberByNameOrId(String memberNameOrId) {
        DistributedMember memberFound = null;

        if (memberNameOrId != null) {
            InternalCache cache = getInternalCache();
            Set<DistributedMember> memberSet = CliUtil.getAllMembers(cache);
            for (DistributedMember member : memberSet) {
                if (memberNameOrId.equalsIgnoreCase(member.getId()) || memberNameOrId.equals(member.getName())) {
                    memberFound = member;
                    break;
                }
            }
        }
        return memberFound;
    }

    public static String stackTraceAsString(Throwable e) {
        String stackAsString = "";
        if (e != null) {
            StringWriter writer = new StringWriter();
            PrintWriter pw = new PrintWriter(writer);
            e.printStackTrace(pw);
            stackAsString = writer.toString();
        }
        return stackAsString;
    }

    @SuppressWarnings("unchecked")
    public static <K> Class<K> forName(String classToLoadName, String neededFor) {
        Class<K> loadedClass = null;
        try {
            // Set Constraints
            ClassPathLoader classPathLoader = ClassPathLoader.getLatest();
            if (classToLoadName != null && !classToLoadName.isEmpty()) {
                loadedClass = (Class<K>) classPathLoader.forName(classToLoadName);
            }
        } catch (ClassNotFoundException | NoClassDefFoundError e) {
            throw new RuntimeException(
                    CliStrings.format(CliStrings.CREATE_REGION__MSG__COULD_NOT_FIND_CLASS_0_SPECIFIED_FOR_1,
                            classToLoadName, neededFor),
                    e);
        } catch (ClassCastException e) {
            throw new RuntimeException(CliStrings.format(
                    CliStrings.CREATE_REGION__MSG__CLASS_SPECIFIED_FOR_0_SPECIFIED_FOR_1_IS_NOT_OF_EXPECTED_TYPE,
                    classToLoadName, neededFor), e);
        }

        return loadedClass;
    }

    public static <K> K newInstance(Class<K> klass, String neededFor) {
        K instance;
        try {
            instance = klass.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(
                    CliStrings.format(CliStrings.CREATE_REGION__MSG__COULD_NOT_INSTANTIATE_CLASS_0_SPECIFIED_FOR_1,
                            klass, neededFor),
                    e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(CliStrings.format(
                    CliStrings.CREATE_REGION__MSG__COULD_NOT_ACCESS_CLASS_0_SPECIFIED_FOR_1, klass, neededFor), e);
        }

        return instance;
    }

    static class CustomFileFilter implements FileFilter {
        private String extensionWithDot;

        public CustomFileFilter(String extensionWithDot) {
            this.extensionWithDot = extensionWithDot;
        }

        @Override
        public boolean accept(File pathname) {
            String name = pathname.getName();
            return name.endsWith(extensionWithDot);
        }
    }

    public static DeflaterInflaterData compressBytes(byte[] input) {
        Deflater compresser = new Deflater();
        compresser.setInput(input);
        compresser.finish();
        byte[] buffer = new byte[100];
        byte[] result = new byte[0];
        int compressedDataLength = 0;
        int totalCompressedDataLength = 0;
        do {
            byte[] newResult = new byte[result.length + buffer.length];
            System.arraycopy(result, 0, newResult, 0, result.length);

            compressedDataLength = compresser.deflate(buffer);
            totalCompressedDataLength += compressedDataLength;
            System.arraycopy(buffer, 0, newResult, result.length, buffer.length);
            result = newResult;
        } while (compressedDataLength != 0);
        return new DeflaterInflaterData(totalCompressedDataLength, result);
    }

    public static DeflaterInflaterData uncompressBytes(byte[] output, int compressedDataLength)
            throws DataFormatException {
        Inflater decompresser = new Inflater();
        decompresser.setInput(output, 0, compressedDataLength);
        byte[] buffer = new byte[512];
        byte[] result = new byte[0];
        int bytesRead;
        while (!decompresser.needsInput()) {
            bytesRead = decompresser.inflate(buffer);
            byte[] newResult = new byte[result.length + bytesRead];
            System.arraycopy(result, 0, newResult, 0, result.length);
            System.arraycopy(buffer, 0, newResult, result.length, bytesRead);
            result = newResult;
        }
        decompresser.end();

        return new DeflaterInflaterData(result.length, result);
    }

    public static class DeflaterInflaterData implements Serializable {
        private static final long serialVersionUID = 1104813333595216795L;

        private final int dataLength;
        private final byte[] data;

        public DeflaterInflaterData(int dataLength, byte[] data) {
            this.dataLength = dataLength;
            this.data = data;
        }

        public int getDataLength() {
            return dataLength;
        }

        public byte[] getData() {
            return data;
        }

        @Override
        public String toString() {
            return String.valueOf(dataLength);
        }
    }

    public static boolean contains(Object[] array, Object object) {
        boolean contains = false;

        if (array != null && object != null) {
            contains = Arrays.asList(array).contains(object);
        }

        return contains;
    }

    /**
     * Returns a set of all the members of the distributed system excluding locators.
     * 
     * @param cache
     */
    @SuppressWarnings("unchecked")
    public static Set<DistributedMember> getAllNormalMembers(InternalCache cache) {
        return new HashSet<DistributedMember>(
                cache.getInternalDistributedSystem().getDistributionManager().getNormalDistributionManagerIds());
    }

    /**
     * Returns a set of all the members of the distributed system including locators.
     * 
     * @param cache
     */
    @SuppressWarnings("unchecked")
    public static Set<DistributedMember> getAllMembers(InternalCache cache) {
        return new HashSet<DistributedMember>(
                cache.getInternalDistributedSystem().getDistributionManager().getDistributionManagerIds());
    }

    @SuppressWarnings("unchecked")
    public static Set<DistributedMember> getAllMembers(InternalDistributedSystem internalDS) {
        return new HashSet<DistributedMember>(internalDS.getDistributionManager().getDistributionManagerIds());
    }

    /**
     * Returns a set of all the members of the distributed system for the given groups.
     */
    public static Set<DistributedMember> getDistributedMembersByGroup(InternalCache cache, String[] groups) {
        Set<DistributedMember> groupMembers = new HashSet<>();
        for (String group : groups) {
            groupMembers
                    .addAll(cache.getInternalDistributedSystem().getDistributionManager().getGroupMembers(group));
        }
        return groupMembers;
    }

    /***
     * Executes a function with arguments on a set of members , ignores the departed members.
     * 
     * @param function Function to be executed.
     * @param args Arguments passed to the function, pass null if you wish to pass no arguments to the
     *        function.
     * @param targetMembers Set of members on which the function is to be executed.
     *
     * @return ResultCollector
     */
    public static ResultCollector<?, ?> executeFunction(final Function function, Object args,
            final Set<DistributedMember> targetMembers) {
        Execution execution;

        if (args != null) {
            execution = FunctionService.onMembers(targetMembers).setArguments(args);
        } else {
            execution = FunctionService.onMembers(targetMembers);
        }

        ((AbstractExecution) execution).setIgnoreDepartedMembers(true);
        return execution.execute(function);
    }

    /***
     * Executes a function with arguments on a member , ignores the departed member.
     * 
     * @param function Function to be executed
     * @param args Arguments passed to the function, pass null if you wish to pass no arguments to the
     *        function.
     * @param targetMember Member on which the function is to be executed.
     * @return ResultCollector
     */
    public static ResultCollector<?, ?> executeFunction(final Function function, Object args,
            final DistributedMember targetMember) {
        Execution execution;

        if (args != null) {
            execution = FunctionService.onMember(targetMember).setArguments(args);
        } else {
            execution = FunctionService.onMember(targetMember);
        }

        ((AbstractExecution) execution).setIgnoreDepartedMembers(true);
        return execution.execute(function);
    }

    /**
     * Returns a Set of DistributedMember for members that have the specified <code>region</code>.
     * <code>returnAll</code> indicates whether to return all members or only the first member we
     * find.
     *
     * @param region region path for which members that have this region are required
     * @param cache cache instance to use to find members
     * @return a Set of DistributedMember for members that have the specified <code>region</code>.
     */
    public static Set<DistributedMember> getRegionAssociatedMembers(String region, final InternalCache cache) {
        if (region == null || region.isEmpty()) {
            return null;
        }

        if (!region.startsWith(Region.SEPARATOR)) {
            region = Region.SEPARATOR + region;
        }

        ManagementService managementService = ManagementService.getExistingManagementService(cache);
        DistributedSystemMXBean distributedSystemMXBean = managementService.getDistributedSystemMXBean();
        Set<DistributedMember> matchedMembers = new HashSet<>();

        Set<DistributedMember> allClusterMembers = new HashSet<>();
        allClusterMembers.addAll(cache.getMembers());
        allClusterMembers.add(cache.getDistributedSystem().getDistributedMember());

        for (DistributedMember member : allClusterMembers) {
            try {
                if (distributedSystemMXBean.fetchRegionObjectName(CliUtil.getMemberNameOrId(member),
                        region) != null) {
                    matchedMembers.add(member);
                }
            } catch (Exception ignored) {
            }
        }
        return matchedMembers;
    }

    public static String getMemberNameOrId(DistributedMember distributedMember) {
        String nameOrId = null;
        if (distributedMember != null) {
            nameOrId = distributedMember.getName();
            nameOrId = nameOrId != null && !nameOrId.isEmpty() ? nameOrId : distributedMember.getId();
        }
        return nameOrId;
    }

    public static String collectionToString(Collection<?> col, int newlineAfter) {
        if (col != null) {
            StringBuilder builder = new StringBuilder();
            int lastNewlineAt = 0;

            for (Iterator<?> it = col.iterator(); it.hasNext();) {
                Object object = it.next();
                builder.append(String.valueOf(object));
                if (it.hasNext()) {
                    builder.append(", ");
                }
                if (newlineAfter > 0 && (builder.length() - lastNewlineAt) / newlineAfter >= 1) {
                    builder.append(GfshParser.LINE_SEPARATOR);
                }
            }
            return builder.toString();
        } else {
            return "" + null;
        }
    }

    public static <T> String arrayToString(T[] array) {
        if (array != null) {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < array.length; i++) {
                Object object = array[i];
                builder.append(String.valueOf(object));
                if (i < array.length - 1) {
                    builder.append(", ");
                }
            }
            return builder.toString();
        } else {
            return "" + null;
        }
    }

    public static String decodeWithDefaultCharSet(String urlToDecode) {
        try {
            return URLDecoder.decode(urlToDecode, Charset.defaultCharset().name());
        } catch (UnsupportedEncodingException e) {
            return urlToDecode;
        }
    }

    /**
     * Resolves file system path relative to Gfsh. If the pathname is not specified, then pathname is
     * returned.
     *
     * @param pathname a String value specifying the file system pathname to resolve.
     * @return a String specifying a path relative to Gfsh.
     */
    public static String resolvePathname(final String pathname) {
        return (StringUtils.isBlank(pathname) ? pathname
                : IOUtils.tryGetCanonicalPathElseGetAbsolutePath(new File(pathname)));
    }

    public static void runLessCommandAsExternalViewer(Result commandResult, boolean isError) {
        StringBuilder sb = new StringBuilder();
        String NEW_LINE = System.getProperty("line.separator");

        while (commandResult.hasNextLine()) {
            sb.append(commandResult.nextLine()).append(NEW_LINE);
        }

        File file = null;
        FileWriter fw;
        try {
            file = File.createTempFile("gfsh_output", "less");
            fw = new FileWriter(file);
            fw.append(sb.toString());
            fw.close();
            File workingDir = file.getParentFile();
            Process p = Runtime.getRuntime()
                    .exec(new String[] { "sh", "-c",
                            "LESSOPEN=\"|color %s\" less -SR " + file.getName() + " < /dev/tty > /dev/tty " }, null,
                            workingDir);
            p.waitFor();
        } catch (IOException | InterruptedException e) {
            Gfsh.printlnErr(e.getMessage());
        } finally {
            if (file != null)
                file.delete();
        }
    }

    public static String getClientIdFromCacheClientProxy(CacheClientProxy p) {
        if (p == null) {
            return null;
        }
        StringBuffer buffer = new StringBuffer();
        buffer.append("[").append(p.getProxyID()).append(":port=").append(p.getRemotePort()).append(":primary=")
                .append(p.isPrimary()).append("]");
        return buffer.toString();
    }

    public static Set<DistributedMember> getMembersForeRegionViaFunction(InternalCache cache, String regionPath,
            boolean returnAll) {
        try {
            Set<DistributedMember> regionMembers = new HashSet<>();
            MembersForRegionFunction membersForRegionFunction = new MembersForRegionFunction();
            FunctionService.registerFunction(membersForRegionFunction);
            Set<DistributedMember> targetMembers = CliUtil.getAllMembers(cache);
            List<?> resultList = (List<?>) CliUtil
                    .executeFunction(membersForRegionFunction, regionPath, targetMembers).getResult();

            for (Object object : resultList) {
                try {
                    if (object instanceof Exception) {
                        LogWrapper.getInstance().warning(
                                "Exception in getMembersForeRegionViaFunction " + ((Throwable) object).getMessage(),
                                ((Throwable) object));
                        continue;
                    } else if (object instanceof Throwable) {
                        LogWrapper.getInstance().warning(
                                "Exception in getMembersForeRegionViaFunction " + ((Throwable) object).getMessage(),
                                ((Throwable) object));
                        continue;
                    }
                    if (object != null) {
                        Map<String, String> memberDetails = (Map<String, String>) object;
                        for (Entry<String, String> entry : memberDetails.entrySet()) {
                            Set<DistributedMember> dsMems = CliUtil.getAllMembers(cache);
                            for (DistributedMember mem : dsMems) {
                                if (mem.getId().equals(entry.getKey())) {
                                    regionMembers.add(mem);
                                    if (!returnAll) {
                                        return regionMembers;
                                    }
                                }
                            }
                        }
                    }
                } catch (Exception ex) {
                    LogWrapper.getInstance().warning("getMembersForeRegionViaFunction exception " + ex);
                }
            }
            return regionMembers;
        } catch (Exception e) {
            LogWrapper.getInstance().warning("getMembersForeRegionViaFunction exception " + e);
            return null;
        }
    }

}