/*
 * Copyright 2017, TeamDev Ltd. All rights reserved.
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package io.spine.gradle.compiler.util;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Collections.emptyList;

/**
 * A utility class which allows to obtain Protobuf file descriptors.
 *
 * @author Alexander Litus
 * @author Alex Tymchenko
 */
public class DescriptorSetUtil {

    private static final String MSG_ENABLE_DESCRIPTOR_SET_GENERATION =
            "Please enable descriptor set generation. See an appropriate section at " +
                    "https://github.com/google/protobuf-gradle-plugin/" +
                    "blob/master/README.md#customize-code-generation-tasks";

    private static final Predicate<FileDescriptorProto> IS_NOT_GOOGLE = new IsNotGoogleProto();

    /** Prevents instantiation of this utility class. */
    private DescriptorSetUtil() {
    }

    /**
     * Returns descriptors of all `.proto` files described in the descriptor set file.
     *
     * @param descriptorSetPath the path to the file generated by `protobuf-gradle-plugin`
     *                          which contains the info about project `.proto` files
     * @return a list of descriptors
     */
    public static Collection<FileDescriptorProto> getProtoFileDescriptors(
            String descriptorSetPath) {
        return getProtoFileDescriptors(
                descriptorSetPath, Predicates.<FileDescriptorProto>alwaysTrue());
    }

    /**
     * Returns descriptors of `.proto` files described in the descriptor set file
     * which match the filter predicate.
     *
     * @param descriptorSetPath the path to the file generated by `protobuf-gradle-plugin`
     *                          which contains the info about project `.proto` files
     * @param filter            a filter predicate to apply to the files
     * @return a list of descriptors
     */
    public static Collection<FileDescriptorProto> getProtoFileDescriptors(
            String descriptorSetPath, Predicate<FileDescriptorProto> filter) {
        if (!new File(descriptorSetPath).exists()) {
            log().warn(MSG_ENABLE_DESCRIPTOR_SET_GENERATION);
            return emptyList();
        }
        final String msg = "Looking up for the proto files matching {} under {}";
        log().trace(msg, filter.getClass()
                               .getSimpleName(), descriptorSetPath);
        final Collection<FileDescriptorProto> fileDescriptors = new LinkedList<>();

        try {
            final FileInputStream fis = new FileInputStream(descriptorSetPath);
            final FileDescriptorSet fileDescriptorSet = FileDescriptorSet.parseFrom(fis);
            for (FileDescriptorProto file : fileDescriptorSet.getFileList()) {
                if (filter.apply(file)) {
                    fileDescriptors.add(file);
                }
            }
        } catch (@SuppressWarnings("OverlyBroadCatchBlock") IOException e) {
            final String errMsg = "Cannot get proto file descriptors. Path = " + descriptorSetPath;
            throw new IllegalStateException(errMsg, e);
        }
        log().trace("Found {} files: {}", fileDescriptors.size(), fileDescriptors);

        return fileDescriptors;
    }

    public static Predicate<FileDescriptorProto> isNotGoogleProto() {
        return IS_NOT_GOOGLE;
    }

    /**
     * Verifies if a package of a file does not contain {@code "google"} in its path.
     */
    private static class IsNotGoogleProto implements Predicate<FileDescriptorProto> {
        @Override
        public boolean apply(@Nullable FileDescriptorProto file) {
            checkNotNull(file);
            final boolean result = !file.getPackage()
                                        .contains("google");
            return result;
        }
    }

    private static Logger log() {
        return LogSingleton.INSTANCE.value;
    }

    private enum LogSingleton {
        INSTANCE;
        @SuppressWarnings("NonSerializableFieldInSerializableClass")
        private final Logger value = LoggerFactory.getLogger(DescriptorSetUtil.class);
    }
}

@@ -1557,16 +1557,81 @@
 otNull;%0A
+import static io.spine.util.Exceptions.newIllegalStateException;%0A
 import s
@@ -1669,16 +1669,16 @@
 tyList;%0A
-
 %0A/**%0A * 
@@ -3054,32 +3054,33 @@
 *%0A     * @param 
+ 
 descriptorSetPat
@@ -3072,32 +3072,47 @@
 escriptorSetPath
+%0A     *        
  the path to the
@@ -3122,33 +3122,39 @@
 le generated by 
-%60
+%7B@code 
 protobuf-gradle-
@@ -3163,56 +3163,39 @@
 ugin
-%60%0A     *                          which contains
+%7D which contains%0A     *        
  the
@@ -3210,32 +3210,38 @@
 out project 
-%60
+%7B@code 
 .proto
-%60
+%7D
  files%0A     
@@ -3253,17 +3253,22 @@
 ram 
+ 
 filter
+%0A 
    
+ *
     
@@ -4425,29 +4425,62 @@
     
-fin
+throw newIlleg
 al
- 
 St
-ring errMsg =
+ateException(%0A                    e,
  %22Ca
@@ -4520,14 +4520,14 @@
 Path
- = %22 +
+: %25s%22,
  des
@@ -4540,17 +4540,16 @@
 rSetPath
-;
 %0A       
@@ -4557,49 +4557,8 @@
     
-throw new IllegalStateException(errMsg, e
 );%0A 
@@ -4985,16 +4985,81 @@
 roto%3E %7B%0A
+%0A        private static final String GOOGLE_PACKAGE = %22google%22;%0A%0A
         
@@ -5271,24 +5271,30 @@
 ontains(
-%22google%22
+GOOGLE_PACKAGE
 );%0A     

Improve code layout