package com.truward.brikar.rpc.support;

import com.truward.brikar.error.model.ErrorV1;
import com.truward.brikar.rpc.RpcMethod;
import com.truward.brikar.rpc.ServletRpcBinding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Abstract base class for RPC bindings.
 */
public abstract class AbstractServletRpcBinding implements ServletRpcBinding {
  public static final String DEFAULT_SERVICE_NAME = "default";

  protected final Logger log = LoggerFactory.getLogger(getClass());

  private final List<HttpMessageConverter<?>> messageConverters;
  private String serviceName = DEFAULT_SERVICE_NAME;

  public AbstractServletRpcBinding(List<HttpMessageConverter<?>> messageConverters) {
    Objects.requireNonNull(messageConverters, "messageConverters");
    final List<HttpMessageConverter<?>> messageConvertersCopy = new ArrayList<>(messageConverters.size());
    for (int i = 0; i < messageConverters.size(); ++i) {
      final HttpMessageConverter<?> messageConverter = messageConverters.get(i);
      if (messageConverter == null) {
        throw new IllegalArgumentException("Null message converter #" + i);
      }
      messageConvertersCopy.add(messageConverter);
    }

    this.messageConverters = messageConvertersCopy;
  }

  public final void setServiceName(@Nonnull String serviceName) {
    this.serviceName = serviceName;
  }

  @Nonnull
  @Override
  public final String getServiceName() {
    return serviceName;
  }

  @Override
  public final void process(@Nullable String urlMethodPath,
                            @Nonnull HttpServletRequest request,
                            @Nonnull HttpServletResponse response) throws IOException {
    // check method - only POST methods are allowed
    if (!HttpMethod.POST.name().equals(request.getMethod())) {
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
      return;
    }

    // get content type
    final MediaType contentType = getMediaType(request, "Content-Type");
    if (contentType == null) {
      response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
      return;
    }

    // get accept type
    MediaType acceptType = getMediaType(request, "Accept");
    acceptType = (acceptType != null ? acceptType : contentType);

    // get method name
    RpcMethod rpcMethod = getRpcMethod(urlMethodPath);
    if (rpcMethod == null) {
      sendError(acceptType, response, HttpServletResponse.SC_NOT_FOUND, "Method not found");
      return;
    }

    // invoke service method
    final Object arg1;
    try {
      arg1 = read(contentType, rpcMethod.getInputType(), new ServletServerHttpRequest(request));
    } catch (HttpMessageNotReadableException e) {
      log.debug("Can't read input message", e);
      sendError(acceptType, response, HttpServletResponse.SC_BAD_REQUEST,
          "Can't read input message");
      return;
    }

    // actually call that method
    try {
      final Object result = rpcMethod.call(arg1);

      // write response
      write(acceptType, rpcMethod.getOutputType(), result,
          new ServletServerHttpResponse(response));
    } catch (Exception e) {
      mapException(e, acceptType, response);
    }

  }

  //
  // Protected
  //

  protected void mapException(Exception e, MediaType acceptType, HttpServletResponse response) throws IOException {
    log.debug("Error", e);
    sendError(acceptType, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal error");
  }

  @Nullable
  protected RpcMethod getRpcMethod(String urlMethodPath) {
    for (final RpcMethod rpcMethod : getExposedMethods()) {
      if (urlMethodPath.equals(rpcMethod.getName())) {
        return rpcMethod;
      }
    }

    return null;
  }

  protected void sendError(MediaType acceptType,
                           HttpServletResponse response,
                           int statusCode,
                           String description) throws IOException {
    response.setStatus(statusCode);
    write(acceptType,
        ErrorV1.ErrorResponse.class,
        ErrorV1.ErrorResponse.newBuilder()
            .setError(ErrorV1.Error.newBuilder()
                .setCode(HttpStatus.valueOf(statusCode).name())
                .setMessage(description)
                .build())
            .build(),
        new ServletServerHttpResponse(response));
  }

  //
  // Private
  //

  @SuppressWarnings("unchecked")
  private Object read(MediaType mediaType, Class<?> clazz, HttpInputMessage inputMessage) throws IOException {
    for (final HttpMessageConverter<?> messageConverter : messageConverters) {
      if (messageConverter.canRead(clazz, mediaType)) {
        return ((HttpMessageConverter<Object>) messageConverter).read(clazz, inputMessage);
      }
    }

    throw new HttpMessageNotReadableException("Unable to read object of type=" + clazz +
        " with mediaType=" + mediaType);
  }

  @SuppressWarnings("unchecked")
  private void write(MediaType mediaType, Class clazz, Object message, HttpOutputMessage outputMessage) throws IOException {
    for (final HttpMessageConverter<?> messageConverter : messageConverters) {
      if (messageConverter.canWrite(clazz, mediaType)) {
        ((HttpMessageConverter<Object>) messageConverter).write(message, mediaType, outputMessage);
        return;
      }
    }

    throw new HttpMessageNotWritableException("Unable to write object of type=" + clazz +
        " with mediaType=" + mediaType);
  }

  // VisibleForTesting
  static MediaType getMediaType(HttpServletRequest request, String headerName) {
    final String mediaTypeName = request.getHeader(headerName);
    if (mediaTypeName == null) {
      return null;
    }

    try {
      return MediaType.valueOf(mediaTypeName);
    } catch (InvalidMediaTypeException ignored) {
      return null;
    }
  }
}


/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2013-2014 sagyf Yang. The Four Group.
 */

package goja.core.libs;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * <p> Images Utils. </p>
 *
 * @author sagyf yang
 * @version 1.0 2014-04-04 10:16
 * @since JDK 1.6
 */
public class Images {

    /**
     * Resize an image
     *
     * @param originalImage The image file
     * @param to            The destination file
     * @param w             The new width (or -1 to proportionally resize)
     * @param h             The new height (or -1 to proportionally resize)
     */
    public static void resize(File originalImage, File to, int w, int h) {
        resize(originalImage, to, w, h, false);
    }

    /**
     * Resize an image
     *
     * @param originalImage The image file
     * @param to            The destination file
     * @param w             The new width (or -1 to proportionally resize) or the maxWidth if keepRatio is true
     * @param h             The new height (or -1 to proportionally resize) or the maxHeight if keepRatio is true
     * @param keepRatio     : if true, resize will keep the original image ratio and use w and h as max
     *                      dimensions
     */
    public static void resize(File originalImage, File to, int w, int h, boolean keepRatio) {
        try {
            BufferedImage source = ImageIO.read(originalImage);
            int owidth = source.getWidth();
            int oheight = source.getHeight();
            double ratio = (double) owidth / oheight;

            int maxWidth = w;
            int maxHeight = h;

            if (w < 0 && h < 0) {
                w = owidth;
                h = oheight;
            }
            if (w < 0 && h > 0) {
                w = (int) (h * ratio);
            }
            if (w > 0 && h < 0) {
                h = (int) (w / ratio);
            }

            if (keepRatio) {
                h = (int) (w / ratio);
                if (h > maxHeight) {
                    h = maxHeight;
                    w = (int) (h * ratio);
                }
                if (w > maxWidth) {
                    w = maxWidth;
                    h = (int) (w / ratio);
                }
            }

            String mimeType = "image/jpeg";
            if (to.getName().endsWith(".png")) {
                mimeType = "image/png";
            }
            if (to.getName().endsWith(".gif")) {
                mimeType = "image/gif";
            }

            // out
            BufferedImage dest = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            Image srcSized = source.getScaledInstance(w, h, Image.SCALE_SMOOTH);
            Graphics graphics = dest.getGraphics();
            graphics.setColor(Color.WHITE);
            graphics.fillRect(0, 0, w, h);
            graphics.drawImage(srcSized, 0, 0, null);
            ImageWriter writer = ImageIO.getImageWritersByMIMEType(mimeType).next();
            ImageWriteParam params = writer.getDefaultWriteParam();
            FileImageOutputStream toFs = new FileImageOutputStream(to);
            writer.setOutput(toFs);
            IIOImage image = new IIOImage(dest, null, null);
            writer.write(null, image, params);
            toFs.flush();
            toFs.close();
            writer.dispose();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Crop an image
     *
     * @param originalImage The image file
     * @param to            The destination file
     * @param x1            The new x origin
     * @param y1            The new y origin
     * @param x2            The new x end
     * @param y2            The new y end
     */
    public static void crop(File originalImage, File to, int x1, int y1, int x2, int y2) {
        try {
            BufferedImage source = ImageIO.read(originalImage);

            String mimeType = "image/jpeg";
            if (to.getName().endsWith(".png")) {
                mimeType = "image/png";
            }
            if (to.getName().endsWith(".gif")) {
                mimeType = "image/gif";
            }
            int width = x2 - x1;
            int height = y2 - y1;

            // out
            BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Image croppedImage = source.getSubimage(x1, y1, width, height);
            Graphics graphics = dest.getGraphics();
            graphics.setColor(Color.WHITE);
            graphics.fillRect(0, 0, width, height);
            graphics.drawImage(croppedImage, 0, 0, null);
            ImageWriter writer = ImageIO.getImageWritersByMIMEType(mimeType).next();
            ImageWriteParam params = writer.getDefaultWriteParam();
            writer.setOutput(new FileImageOutputStream(to));
            IIOImage image = new IIOImage(dest, null, null);
            writer.write(null, image, params);
            writer.dispose();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Encode an image to base64 using a data: URI
     *
     * @param image The image file
     * @return The base64 encoded value
     */
    public static String toBase64(File image) throws IOException {
        return "data:" + MimeTypes.getMimeType(image.getName()) + ";base64," + Codec.encodeBASE64(
                IO.readContent(image));
    }

    /**
     * 将指定的图片加入到当前图片中的指定位置. 即向图片中打水印.
     *
     * @param file     要添加的图片文件。
     * @param position 要添加的图片在当前图片中的位置. <br /> 其取值范围为1-9之间的整数(默认为9)。分别代表：左上、上中、右上、左中、正中、右中、左下、中下、右下
     */
    public void add(File dest, File file, int position) {
        if (dest.exists() && !dest.isDirectory()) {
            String fn = file.getName().toLowerCase();
            int opacityType = fn.endsWith(".png") || fn.endsWith("gif") ?
                    BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
            Image destImg;
            try {
                destImg = ImageIO.read(dest);
            } catch (IllegalArgumentException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            int width = destImg.getWidth(null);
            int height = destImg.getHeight(null);

            final BufferedImage image = new BufferedImage(width, height, opacityType);

            Image src;
            try {
                src = ImageIO.read(file);
            } catch (IllegalArgumentException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            int ww = src.getWidth(null);
            int hh = src.getHeight(null);
            int WW, HH;
            switch (position) {
                case 1:
                    WW = 0;
                    HH = 0;
                    break;
                case 2:
                    WW = (width - ww) / 2;
                    HH = 0;
                    break;
                case 3:
                    WW = width - ww;
                    HH = 0;
                    break;
                case 4:
                    WW = 0;
                    HH = (height - hh) / 2;
                    break;
                case 5:
                    WW = (width - ww) / 2;
                    HH = (height - hh) / 2;
                    break;
                case 6:
                    WW = width - ww;
                    HH = (height - hh) / 2;
                    break;
                case 7:
                    WW = 0;
                    HH = height - hh;
                    break;
                case 8:
                    WW = (width - ww) / 2;
                    HH = height - hh;
                    break;
                default:
                    WW = width - ww;
                    HH = height - hh;
            }
            Graphics g = image.createGraphics();
            g.drawImage(src, WW, HH, ww, hh, null);
            g.dispose();
        }
    }
}


// Copyright (c) 2003-2014, Jodd Team (jodd.org). All Rights Reserved.

package goja.core.kits;

import goja.core.StringPool;

import java.util.Map;

/**
 * Parser for string macro templates. On parsing, macro values in provided string are resolved and
 * replaced with real values. Once set, one string template parser can be reused for parsing, even
 * using different macro resolvers.
 */
public class StrTemplateKit {

    public static final String  DEFAULT_MACRO_START = "${";
    // ---------------------------------------------------------------- properties
    public static final String  DEFAULT_MACRO_END   = "}";
    protected           String  macroStart          = DEFAULT_MACRO_START;
    protected           String  macroEnd            = DEFAULT_MACRO_END;
    protected           boolean replaceMissingKey   = true;
    protected String missingKeyReplacement;
    protected boolean resolveEscapes = true;
    protected char    escapeChar     = '\\';
    protected boolean parseValues;

    /**
     * Finds first occurrence of a substring in the given source but within limited range [start,
     * end). It is fastest possible code, but still original String.indexOf(String, int)
     * is much faster (since it uses char[] value directly) and should be used when no range is
     * needed.
     *
     * @param src        source string for examination
     * @param sub        substring to find
     * @param startIndex starting index
     * @param endIndex   ending index
     * @return index of founded substring or -1 if substring not found
     */
    public static int indexOf(String src, String sub, int startIndex, int endIndex) {
        if (startIndex < 0) {
            startIndex = 0;
        }
        int srclen = src.length();
        if (endIndex > srclen) {
            endIndex = srclen;
        }
        int sublen = sub.length();
        if (sublen == 0) {
            return startIndex > srclen ? srclen : startIndex;
        }

        int total = endIndex - sublen + 1;
        char c = sub.charAt(0);
        mainloop:
        for (int i = startIndex; i < total; i++) {
            if (src.charAt(i) != c) {
                continue;
            }
            int j = 1;
            int k = i + 1;
            while (j < sublen) {
                if (sub.charAt(j) != src.charAt(k)) {
                    continue mainloop;
                }
                j++;
                k++;
            }
            return i;
        }
        return -1;
    }

    /**
     * Creates commonly used {@link StrTemplateKit.MacroResolver} that resolved macros in the
     * provided map.
     */
    public static MacroResolver createMapMacroResolver(final Map map) {
        return new MacroResolver() {
            @Override
            public String resolve(String macroName) {
                Object value = map.get(macroName);

                if (value == null) {
                    return null;
                }

                return value.toString();
            }
        };
    }

    public boolean isReplaceMissingKey() {
        return replaceMissingKey;
    }

    /**
     * Specifies if missing keys should be resolved at all, true by default. If
     * false missing keys will be left as it were, i.e. they will not be replaced.
     */
    public void setReplaceMissingKey(boolean replaceMissingKey) {
        this.replaceMissingKey = replaceMissingKey;
    }

    public String getMissingKeyReplacement() {
        return missingKeyReplacement;
    }

    /**
     * Specifies replacement for missing keys. If null exception will be thrown.
     */
    public void setMissingKeyReplacement(String missingKeyReplacement) {
        this.missingKeyReplacement = missingKeyReplacement;
    }

    public boolean isResolveEscapes() {
        return resolveEscapes;
    }

    /**
     * Specifies if escaped values should be resolved. In special usecases, when the same string has
     * to be processed more then once, this may be set to false so escaped values
     * remains.
     */
    public void setResolveEscapes(boolean resolveEscapes) {
        this.resolveEscapes = resolveEscapes;
    }

    public String getMacroStart() {
        return macroStart;
    }

    /**
     * Defines macro start string.
     */
    public void setMacroStart(String macroStart) {
        this.macroStart = macroStart;
    }

    public String getMacroEnd() {
        return macroEnd;
    }

    /**
     * Defines macro end string.
     */
    public void setMacroEnd(String macroEnd) {
        this.macroEnd = macroEnd;
    }

    public char getEscapeChar() {
        return escapeChar;
    }

    /**
     * Defines escape character.
     */
    public void setEscapeChar(char escapeChar) {
        this.escapeChar = escapeChar;
    }

    // ---------------------------------------------------------------- parse

    public boolean isParseValues() {
        return parseValues;
    }

    /**
     * Defines if macro values has to be parsed, too. By default, macro values are returned as they
     * are.
     */
    public void setParseValues(boolean parseValues) {
        this.parseValues = parseValues;
    }

    // ---------------------------------------------------------------- resolver

    /**
     * Parses string template and replaces macros with resolved values.
     */
    public String parse(String template, MacroResolver macroResolver) {
        StringBuilder result = new StringBuilder(template.length());

        int i = 0;
        int len = template.length();

        int startLen = macroStart.length();
        int endLen = macroEnd.length();

        while (i < len) {
            int ndx = template.indexOf(macroStart, i);
            if (ndx == -1) {
                result.append(i == 0 ? template : template.substring(i));
                break;
            }

            // check escaped
            int j = ndx - 1;
            boolean escape = false;
            int count = 0;

            while ((j >= 0) && (template.charAt(j) == escapeChar)) {
                escape = !escape;
                if (escape) {
                    count++;
                }
                j--;
            }
            if (resolveEscapes) {
                result.append(template.substring(i, ndx - count));
            } else {
                result.append(template.substring(i, ndx));
            }
            if (escape) {
                result.append(macroStart);
                i = ndx + startLen;
                continue;
            }

            // find macros end
            ndx += startLen;
            int ndx2 = template.indexOf(macroEnd, ndx);
            if (ndx2 == -1) {
                throw new IllegalArgumentException(
                        "Invalid template, unclosed macro at: " + (ndx - startLen));
            }

            // detect inner macros, there is no escaping
            int ndx1 = ndx;
            while (ndx1 < ndx2) {
                int n = indexOf(template, macroStart, ndx1, ndx2);
                if (n == -1) {
                    break;
                }
                ndx1 = n + startLen;
            }

            String name = template.substring(ndx1, ndx2);

            // find value and append
            Object value;
            if (missingKeyReplacement != null || !replaceMissingKey) {
                try {
                    value = macroResolver.resolve(name);
                } catch (Exception ignore) {
                    value = null;
                }

                if (value == null) {
                    if (replaceMissingKey) {
                        value = missingKeyReplacement;
                    } else {
                        value = template.substring(ndx1 - startLen, ndx2 + 1);
                    }
                }
            } else {
                value = macroResolver.resolve(name);
                if (value == null) {
                    value = StringPool.EMPTY;
                }
            }

            if (ndx == ndx1) {
                String stringValue = value.toString();
                if (parseValues) {
                    if (stringValue.contains(macroStart)) {
                        stringValue = parse(stringValue, macroResolver);
                    }
                }
                result.append(stringValue);
                i = ndx2 + endLen;
            } else {
                // inner macro
                template = template.substring(0, ndx1 - startLen) + value.toString() + template.substring(
                        ndx2 + endLen);
                len = template.length();
                i = ndx - startLen;
            }
        }
        return result.toString();
    }

    /**
     * Macro value resolver.
     */
    public interface MacroResolver {
        /**
         * Resolves macro value for macro name founded in string template. null values will
         * be replaced with empty strings.
         */
        String resolve(String macroName);
    }
}


/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2013-2014 sagyf Yang. The Four Group.
 */

package goja;

import goja.core.app.ApplicationMode;
import goja.core.app.GojaConfig;
import goja.core.exceptions.GojaException;
import goja.core.exceptions.UnexpectedException;
import goja.core.libs.Action;
import goja.core.libs.PThreadFactory;
import goja.core.libs.Promise;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * <p> . </p>
 *
 * @author sagyf yang
 * @version 1.0 2014-06-24 22:05
 * @since JDK 1.6
 */
@SuppressWarnings("UnusedDeclaration")
public final class Invoker {

    private static final Logger                      logger   = LoggerFactory.getLogger(Invoker.class);
    /**
     * Main executor for requests invocations.
     */
    public static        ScheduledThreadPoolExecutor executor = null;

    /**
     * Init executor at load time.
     */
    static {
        int core = GojaConfig.getPropertyToInt("goja.pool", GojaConfig.getApplicationMode().isDev() ? 1
                : (Runtime.getRuntime().availableProcessors() + 1));
        executor = new ScheduledThreadPoolExecutor(core, new PThreadFactory("goja"),
                new ThreadPoolExecutor.AbortPolicy());
    }

    private Invoker() {
    }

    /**
     * Run the code in a new thread took from a thread pool.
     *
     * @param invocation The code to run
     * @return The future object, to know when the task is completed
     */
    public static Future<?> invoke(final Invocation invocation) {
        return executor.submit(invocation);
    }

    /**
     * Run the code in a new thread after a delay
     *
     * @param invocation The code to run
     * @param millis     The time to wait before, in milliseconds
     * @return The future object, to know when the task is completed
     */
    public static Future<?> invoke(final Invocation invocation, long millis) {
        return executor.schedule(invocation, millis, TimeUnit.MILLISECONDS);
    }

    /**
     * Run the code in the same thread than caller.
     *
     * @param invocation The code to run
     */
    public static void invokeInThread(DirectInvocation invocation) {
        boolean retry = true;
        while (retry) {
            invocation.run();
            if (invocation.retry == null) {
                retry = false;
            } else {
                try {
                    if (invocation.retry.task != null) {
                        invocation.retry.task.get();
                    } else {
                        Thread.sleep(invocation.retry.timeout);
                    }
                } catch (Exception e) {
                    throw new UnexpectedException(e);
                }
                retry = true;
            }
        }
    }

    /**
     * The class/method that will be invoked by the current operation
     */
    public static class InvocationContext {

        public static ThreadLocal<InvocationContext> current = new ThreadLocal<InvocationContext>();
        private final List<Annotation> annotations;
        private final String           invocationType;

        public InvocationContext(String invocationType) {
            this.invocationType = invocationType;
            this.annotations = new ArrayList<Annotation>();
        }

        public InvocationContext(String invocationType, List<Annotation> annotations) {
            this.invocationType = invocationType;
            this.annotations = annotations;
        }

        public InvocationContext(String invocationType, Annotation[] annotations) {
            this.invocationType = invocationType;
            this.annotations = Arrays.asList(annotations);
        }

        public InvocationContext(String invocationType, Annotation[]... annotations) {
            this.invocationType = invocationType;
            this.annotations = new ArrayList<Annotation>();
            for (Annotation[] some : annotations) {
                this.annotations.addAll(Arrays.asList(some));
            }
        }

        public static InvocationContext current() {
            return current.get();
        }

        public List<Annotation> getAnnotations() {
            return annotations;
        }

        @SuppressWarnings("unchecked")
        public <T extends Annotation> T getAnnotation(Class<T> clazz) {
            for (Annotation annotation : annotations) {
                if (annotation.annotationType().isAssignableFrom(clazz)) {
                    return (T) annotation;
                }
            }
            return null;
        }

        public <T extends Annotation> boolean isAnnotationPresent(Class<T> clazz) {
            for (Annotation annotation : annotations) {
                if (annotation.annotationType().isAssignableFrom(clazz)) {
                    return true;
                }
            }
            return false;
        }

        /**
         * Returns the InvocationType for this invocation - Ie: A plugin can use this to find out if
         * it runs in the context of a background Job
         */
        public String getInvocationType() {
            return invocationType;
        }

        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append("InvocationType: ");
            builder.append(invocationType);
            builder.append(". annotations: ");
            for (Annotation annotation : annotations) {
                builder.append(annotation.toString()).append(",");
            }
            return builder.toString();
        }
    }

    /**
     * An Invocation in something to run in a Play! context
     */
    public static abstract class Invocation implements Runnable {

        /**
         * Override this method
         */
        public abstract void execute() throws Exception;

        /**
         * Needs this method to do stuff *before* init() is executed. The different
         * Invocation-implementations does a lot of stuff in init() and they might do it before
         * calling super.init()
         */
        protected void preInit() {
            // clear language for this request - we're resolving it later when it is needed
            //            I18n.clear();
        }

        /**
         * Init the call (especially usefull in DEV mode to detect changes)
         */
        public boolean init() {
            Thread.currentThread().setContextClassLoader(Goja.class.getClassLoader());
            if (!Goja.started) {
                if (GojaConfig.getApplicationMode() == ApplicationMode.PROD) {
                    throw new UnexpectedException("Application is not started");
                }
            }
            InvocationContext.current.set(getInvocationContext());
            return true;
        }

        public abstract InvocationContext getInvocationContext();

        /**
         * Things to do before an Invocation
         */
        public void before() {
            Thread.currentThread().setContextClassLoader(Goja.class.getClassLoader());
        }

        /**
         * Things to do after an Invocation. (if the Invocation code has not thrown any exception)
         */
        public void after() {
        }

        /**
         * Things to do when the whole invocation has succeeded (before + execute + after)
         */
        public void onSuccess() throws Exception {
        }

        /**
         * Things to do if the Invocation code thrown an exception
         */
        public void onException(Throwable e) {
            if (e instanceof GojaException) {
                throw (GojaException) e;
            }
            throw new UnexpectedException(e);
        }

        /**
         * The request is suspended
         */
        public void suspend(Suspend suspendRequest) {
            if (suspendRequest.task != null) {
                WaitForTasksCompletion.waitFor(suspendRequest.task, this);
            } else {
                Invoker.invoke(this, suspendRequest.timeout);
            }
        }

        /**
         * Things to do in all cases after the invocation.
         */
        public void _finally() {
            InvocationContext.current.remove();
        }

        /**
         * It's time to execute.
         */
        public void run() {
            try {
                preInit();
                if (init()) {
                    before();
                    execute();
                    after();
                    onSuccess();
                }
            } catch (Suspend e) {
                suspend(e);
                after();
            } catch (Throwable e) {
                onException(e);
            } finally {
                _finally();
            }
        }
    }

    /**
     * A direct invocation (in the same thread than caller)
     */
    public static abstract class DirectInvocation extends Invocation {

        public static final String invocationType = "DirectInvocation";

        Suspend retry = null;

        @Override
        public boolean init() {
            retry = null;
            return super.init();
        }

        @Override
        public void suspend(Suspend suspendRequest) {
            retry = suspendRequest;
        }

        @Override
        public InvocationContext getInvocationContext() {
            return new InvocationContext(invocationType);
        }
    }

    /**
     * Throwable to indicate that the request must be suspended
     */
    @SuppressWarnings("UnusedDeclaration")
    public static class Suspend extends GojaException {

        private static final long serialVersionUID = 4876949569944002423L;
        /**
         * Suspend for a timeout (in milliseconds).
         */
        long timeout;

        /**
         * Wait for task execution.
         */
        Future<?> task;

        public Suspend(long timeout) {
            this.timeout = timeout;
        }

        public Suspend(Future<?> task) {
            this.task = task;
        }

        @Override
        public String getErrorTitle() {
            return "Request is suspended";
        }

        @Override
        public String getErrorDescription() {
            if (task != null) {
                return "Wait for " + task;
            }
            return "Retry in " + timeout + " ms.";
        }
    }

    /**
     * Utility that track tasks completion in order to resume suspended requests.
     */
    static class WaitForTasksCompletion extends Thread {

        static WaitForTasksCompletion instance;
        Map<Future<?>, Invocation> queue;

        public WaitForTasksCompletion() {
            queue = new ConcurrentHashMap<Future<?>, Invocation>();
            setName("WaitForTasksCompletion");
            setDaemon(true);
        }

        public static <V> void waitFor(Future<V> task, final Invocation invocation) {
            if (task instanceof Promise) {
                Promise<V> smartFuture = (Promise<V>) task;
                smartFuture.onRedeem(new Action<Promise<V>>() {
                    public void invoke(Promise<V> result) {
                        executor.submit(invocation);
                    }
                });
            } else {
                synchronized (WaitForTasksCompletion.class) {
                    if (instance == null) {
                        instance = new WaitForTasksCompletion();
                        logger.warn("Start WaitForTasksCompletion");
                        instance.start();
                    }
                    instance.queue.put(task, invocation);
                }
            }
        }

        @Override
        public void run() {
            while (true) {
                try {
                    if (!queue.isEmpty()) {
                        for (Future<?> task : new HashSet<Future<?>>(queue.keySet())) {
                            if (task.isDone()) {
                                executor.submit(queue.get(task));
                                queue.remove(task);
                            }
                        }
                    }
                    Thread.sleep(50);
                } catch (InterruptedException ex) {
                    logger.warn("While waiting for task completions", ex);
                }
            }
        }
    }
}


package com.truward.brikar.client.rest;

import com.truward.brikar.client.interceptor.RequestLogAwareHttpRequestInterceptor;
import com.truward.brikar.client.interceptor.RequestLogAwareHttpResponseInterceptor;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * A helper class that pre configures RestOperations and underlying HTTP client to use the specified connection
 * settings.
 *
 * @author Alexander Shabanov
 */
public final class RestOperationsFactory implements DisposableBean, AutoCloseable {
  /**
   * Default connection ttl setting. Should be less than server we're going to use.
   * Since this class is intended to be used mostly for interacting with brikar services, this TTL
   * setting should be set keeping in mind default 'keep alive' settings in brikar-server module.
   *
   * Since we're using jetty and default jetty's TTL is defined to 200000 - see _maxIdleTime in
   * org.eclipse.jetty.server.AbstractConnector class.
   *
   * We're picking slightly smaller value here to use jetty's resources in the most efficient way.
   */
  public static final long DEFAULT_CONNECTION_TTL = 60000L;

  /**
   * Default value for total maximum connections.
   */
  public static final int DEFAULT_MAX_CONN_TOTAL = 15;

  /**
   * Use logger with specified name - 'BrikarRestClient' that should be associated with all HTTP calls.
   */
  private final Logger log = LoggerFactory.getLogger("BrikarRestClient");

  private final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
  private final List<HttpMessageConverter<?>> messageConverters;
  private HttpComponentsClientHttpRequestFactory httpRequestFactory;
  private long connectionTtlMillis;
  private int maxConnTotal;
  private HttpRequestRetryHandler retryHandler;

  public RestOperationsFactory(@Nonnull List<HttpMessageConverter<?>> messageConverters) {
    this.messageConverters = messageConverters;
    setConnectionTtlMillis(DEFAULT_CONNECTION_TTL);
    setMaxConnTotal(DEFAULT_MAX_CONN_TOTAL);
    setRetryHandler(null);
  }

  public RestOperationsFactory(@Nonnull HttpMessageConverter<?>... messageConverters) {
    this(Arrays.asList(messageConverters));
  }

  /**
   * If set before bean is initialized, instructs to use the provided connection time to live value
   * that should be given in milliseconds.
   * If the provided value is negative, then no value will be set and default http client connection TTL settings will
   * be used which sets TTL to infitity.
   *
Should be set prior to {@link #getRestOperations()} to take an effect.

   *
   * @param connectionTtlMillis Connection time to live, in milliseconds
   */
  public void setConnectionTtlMillis(long connectionTtlMillis) {
    this.connectionTtlMillis = connectionTtlMillis;
  }

  /**
   * If set before bean is initialized, instructs to use provided value as maximum connections.
   *
Should be set prior to {@link #getRestOperations()} to take an effect.

   *
   * @param maxConnTotal Maximum total connections
   */
  public void setMaxConnTotal(int maxConnTotal) {
    this.maxConnTotal = maxConnTotal;
  }

  /**
   * Sets retry handler, that should be used for handling connectivity issues.
   *
Should be set prior to {@link #getRestOperations()} to take an effect.

   *
   * @param retryHandler Retry handler
   */
  public void setRetryHandler(@Nullable HttpRequestRetryHandler retryHandler) {
    this.retryHandler = retryHandler;
  }

  /**
   * Sets credentials for use when accessing service APIs.
   * Note, that multiple calls to this method override previously set credentials.
   *
   * @param credentials Credential list to use
   */
  public void setCredentials(@Nonnull List<ServiceClientCredentials> credentials) {
    credentialsProvider.clear();

    for (final ServiceClientCredentials cred : credentials) {
      final URI uri = cred.getBaseUri();
      credentialsProvider.setCredentials(new AuthScope(
              new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme())),
          new UsernamePasswordCredentials(cred.getUsername(), cred.getPassword().toString()));
    }
  }

  /**
   * Returns rest operations object, suitable for use with the specified credentials
   *
   * @return New instance of {@link RestOperations} with all the connection settings provided prior to calling this
   */
  @Nonnull
  public RestOperations getRestOperations() {
    final HttpClientBuilder builder = HttpClientBuilder.create();
    initDefaultHttpClientBuilder(builder);

    httpRequestFactory = new HttpComponentsClientHttpRequestFactory(builder.build());
    final RestTemplate restTemplate = new RestTemplate(messageConverters);
    restTemplate.setRequestFactory(httpRequestFactory);
    return restTemplate;
  }

  @Override
  public void close() {
    if (httpRequestFactory != null) {
      try {
        httpRequestFactory.destroy();
      } catch (Exception e) {
        log.error("Error while shutting down httpRequestFactory", e);
      }
      httpRequestFactory = null;
    }
  }

  @Override
  public void destroy() {
    close();
  }

  //
  // Protected
  //

  protected void initTimings(@Nonnull HttpClientBuilder builder) {
    // copy settings
    final long connTtl = this.connectionTtlMillis;
    if (connTtl >= 0) {
      // don't store connection for more than given amount of milliseconds
      builder.setConnectionTimeToLive(connTtl, TimeUnit.MILLISECONDS);
    }
    builder.setMaxConnTotal(maxConnTotal);
  }

  protected void initCredentialsProvider(@Nonnull HttpClientBuilder builder) {
    // use builtin credentials provider
    builder.setDefaultCredentialsProvider(credentialsProvider);
  }

  protected void initRetryHandler(@Nonnull HttpClientBuilder builder) {
    HttpRequestRetryHandler retryHandler = this.retryHandler;
    if (retryHandler == null) {
      retryHandler = new DefaultHttpRequestRetryHandler(3, true);
    }

    builder.setRetryHandler(retryHandler);
  }

  protected void initRequestVectorOperations(@Nonnull HttpClientBuilder builder) {
    builder.addInterceptorLast(new RequestLogAwareHttpRequestInterceptor());
    builder.addInterceptorLast(new RequestLogAwareHttpResponseInterceptor(log));
  }

  protected void initDefaultHttpClientBuilder(@Nonnull HttpClientBuilder builder) {
    initRequestVectorOperations(builder);
    initTimings(builder);
    initCredentialsProvider(builder);
    initRetryHandler(builder);
  }
}


/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2013-2014 sagyf Yang. The Four Group.
 */

package goja.mvc;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;

import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;

import org.joda.time.DateTime;

import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import goja.core.dto.PageDto;
import goja.core.kits.lang.DateKit;
import goja.mvc.datatables.DTCriterias;
import goja.mvc.datatables.DTDao;
import goja.mvc.datatables.DTResponse;
import goja.mvc.easyui.EuiDataGrid;
import goja.mvc.easyui.req.DataGridReq;
import goja.mvc.kits.Requests;
import goja.mvc.render.NotModified;
import goja.security.goja.SecurityKit;
import goja.security.shiro.AppUser;
import goja.security.shiro.Securitys;

import static goja.core.StringPool.SLASH;

/**
 *
 Controller.

 *
 * @author sagyf yang
 * @version 1.0 2014-06-01 20:29
 * @since JDK 1.6
 */
public class Controller extends com.jfinal.core.Controller {

    /**
     * Send a 304 Not Modified response
     */
    protected static void notModified() {
        new NotModified().render();
    }

    /**
     * Rendering errors information, in Json format.
     *
     * @param error error message.
     */
    protected void renderAjaxError(String error) {
        renderJson(AjaxMessage.error(error));
    }

    /**
     * Rendering errors information, in Json format.
     *
     * @param data error data.
     */
    protected <T> void renderAjaxError(T data) {
        renderJson(AjaxMessage.error(data));
    }

    /**
     * Rendering errors information, in Json format.
     *
     * @param error errors information.
     * @param e     exception.
     */
    protected void renderAjaxError(String error, Exception e) {
        renderJson(AjaxMessage.error(error, e));
    }

    /**
     * In the form of JSON rendering failure information.
     *
     * @param failure failure information.
     */
    protected void renderAjaxFailure(String failure) {
        renderJson(AjaxMessage.failure(failure));
    }

    /**
     * In the form of JSON rendering failure information.
     */
    protected void renderAjaxFailure() {
        renderJson(AjaxMessage.FAILURE);
    }

    /**
     * In the form of JSON rendering forbidden information.
     */
    protected void renderAjaxForbidden() {
        renderJson(AjaxMessage.FORBIDDEN);
    }

    /**
     * In the form of JSON rendering forbidden information.
     *
     * @param data the forbidden data.
     * @param <T>  Generic parameter.
     */
    protected <T> void renderAjaxForbidden(T data) {
        renderJson(AjaxMessage.forbidden(data));
    }

    /**
     * In the form of JSON rendering forbidden information.
     *
     * @param message the forbidden message.
     * @param data    the forbidden data.
     * @param <T>     Generic parameter.
     */
    protected <T> void renderAjaxForbidden(String message, T data) {
        renderJson(AjaxMessage.forbidden(message, data));
    }

    /**
     * In the form of JSON rendering success information.
     *
     * @param message success information.
     */
    protected void renderAjaxSuccess(String message) {
        renderJson(AjaxMessage.ok(message));
    }

    /**
     * In the form of JSON rendering default success information.
     */
    protected void renderAjaxSuccess() {
        renderJson(AjaxMessage.OK);
    }

    /**
     * With the success of data information.
     *
     * @param data the render data.
     * @param <T>  Generic parameter.
     */
    protected <T> void renderAjaxSuccess(T data) {
        renderJson(AjaxMessage.ok(data));
    }

    protected <T> void renderAjaxSuccess(List<T> list) {
        if (list == null || list.isEmpty()) {
            renderJson(AjaxMessage.nodata());
        } else {
            renderJson(AjaxMessage.ok(list));
        }
    }

    /**
     * News Ajax rendering not logged in.
     */
    protected void renderAjaxNologin() {
        renderJson(AjaxMessage.nologin());
    }

    /**
     * News Ajax rendering not logged in.
     *
     * @param data the render data.
     * @param <T>  Generic parameter.
     */
    protected <T> void renderAjaxNologin(T data) {
        renderJson(AjaxMessage.nologin(data));
    }

    /**
     * Render the empty data.
     */
    protected void renderAjaxNodata() {
        renderJson(AjaxMessage.NODATA);
    }

    /**
     * Render the specified view as a string.
     *
     * @param view view template.
     * @return the string.
     */
    protected String renderTpl(String view) {
        return template(view);
    }

    /**
     * Render view as a string
     *
     * @param view view
     * @return render string.
     */
    protected String template(String view) {
        final Enumeration<String> attrs = getAttrNames();
        final Map<String, Object> root = Maps.newHashMap();
        while (attrs.hasMoreElements()) {
            String attrName = attrs.nextElement();
            root.put(attrName, getAttr(attrName));
        }
        return Freemarkers.processString(view, root);
    }

    /**
     * Renderingtodo prompt
     */
    protected void renderTODO() {
        renderJson(AjaxMessage.developing());
    }

    /**
     * Based on the current path structure is going to jump full Action of the path
     *
     * @param currentActionPath The current path, similar to/sau/index
     * @param url               The next path, similar to/au/login, the detail? The admin/detail.
     * @return An Action under the full path.
     */
    protected String parsePath(String currentActionPath, String url) {
        if (url.startsWith(SLASH)) {
            return url.split("\\?")[0];
        } else if (!url.contains(SLASH)) {
            return SLASH + currentActionPath.split(SLASH)[1] + SLASH + url.split("\\?")[0];
        } else if (url.contains("http:") || url.contains("https:")) {
            return null;
        }
        ///abc/def","bcd/efg?abc
        return currentActionPath + SLASH + url.split("\\?")[0];
    }

    /**
     * The Request is ajax with return true.
     *
     * @return true the request is ajax request.
     */
    protected boolean isAjax() {
        return Requests.ajax(getRequest());
    }

    /**
     * Get parameters from the Request and encapsulation as an object for processing。
     *
     * @return jquery DataTables
     */
    protected DTCriterias getCriterias() {
        return DTCriterias.criteriasWithRequest(getRequest());
    }

    /**
     * According to the request information of jquery.Datatables, the results of the query and
     * returns the JSON data to the client.
 The specified query set the data.
     *
     * @param datas     The data.
     * @param criterias datatable criterias.
     * @param <E>       Generic parameter.
     */
    protected <E> void renderDataTables(DTCriterias criterias, Page<E> datas) {
        Preconditions.checkNotNull(criterias, "datatable criterias is must be not null.");
        DTResponse<E> response =
                DTResponse.build(criterias, datas.getList(), datas.getTotalRow(), datas.getTotalPage());
        renderJson(response);
    }

    /**
     * According to the request information of jquery.Datatables, the results of the query and
     * returns the JSON data to the client.
 Automatically according to the request to create
     * the query SQL and encapsulating the results back to the client.
     *
     * @param m_cls     The Model class.
     * @param criterias datatable criterias.
     */
    protected void renderDataTables(DTCriterias criterias, Class<? extends Model> m_cls) {
        Preconditions.checkNotNull(criterias, "datatable criterias is must be not null.");
        DTResponse response = criterias.response(m_cls);
        renderJson(response);
    }

    /**
     * According to the request information of jquery.Datatables, the results of the query and
     * returns the JSON data to the client.
 According to the SQL configuration file, in
     * accordance with the Convention model_name.coloumns\model_name.where\model_name.order
     * configured SQL to query and returns the results to the client.
     *
     * @param model_name The Model name.
     * @param criterias  datatable criterias.
     */
    protected void renderDataTables(DTCriterias criterias, String model_name) {
        Preconditions.checkNotNull(criterias, "datatable criterias is must be not null.");
        final Page<Record> datas = DTDao.paginate(model_name, criterias);
        DTResponse response =
                DTResponse.build(criterias, datas.getList(), datas.getTotalRow(), datas.getTotalRow());
        renderJson(response);
    }

    /**
     * According to the request information of jquery.Datatables, the results of the query and
     * returns the JSON data to the client.
 According to the SQL configuration file, in
     * accordance with the Convention model_name.coloumns\model_name.where\model_name.order
     * configured SQL to query and specify the parameters and return results to the client.
     *
     * @param criterias    datatable criterias.
     * @param sqlGroupName The Model name.
     * @param params       Query parameters
     */
    protected void renderDataTables(DTCriterias criterias, String sqlGroupName, List<Object> params) {
        Preconditions.checkNotNull(criterias, "datatable criterias is must be not null.");
        final Page<Record> datas = DTDao.paginate(sqlGroupName, criterias, params);
        DTResponse response =
                DTResponse.build(criterias, datas.getList(), datas.getTotalRow(), datas.getTotalRow());
        renderJson(response);
    }

    /**
     * The source of data for rendering the jQuery Datatables
     *
     * @param m_cls The Model class.
     */
    protected void renderDataTables(Class<? extends Model> m_cls) {
        DTCriterias criterias = getCriterias();
        Preconditions.checkNotNull(criterias, "datatable criterias is must be not null.");
        DTResponse response = criterias.response(m_cls);
        renderJson(response);
    }

    /**
     * rendering the empty datasource.
     *
     * @param criterias datatable criterias.
     */
    protected void renderEmptyDataTables(DTCriterias criterias) {
        Preconditions.checkNotNull(criterias, "datatable criterias is must be not null.");
        DTResponse response = DTResponse.build(criterias, Collections.EMPTY_LIST, 0, 0);
        renderJson(response);
    }

    /**
     * 获取EasyUI Datagrid 的表格参数
     *
     * @return 表格请求参数
     */
    protected Optional<DataGridReq> getEuiDGReq() {
        return EuiDataGrid.req(getRequest());
    }

    /**
     * 渲染DataGrid的表格展示，支持排序和搜索
     *
     * @param modelClass 指定类
     */
    protected void renderEasyUIDataGrid(Class<? extends Model> modelClass) {
        final Optional<DataGridReq> reqOptional = EuiDataGrid.req(getRequest());
        if (reqOptional.isPresent()) {
            renderJson(EuiDataGrid.rsp(reqOptional.get(), modelClass));
        } else {
            renderJson(EuiDataGrid.EMPTY_DATAGRID);
        }
    }

    /**
     * 渲染DataGrid的表格展示，支持排序和搜索
     *
     * @param gridReq      请求参数
     * @param sqlGroupName 指定SQL管理的GroupName
     */
    protected void renderEasyUIDataGrid(DataGridReq gridReq, String sqlGroupName) {
        Preconditions.checkNotNull(gridReq, "参数不能为空");
        renderJson(EuiDataGrid.rsp(gridReq, sqlGroupName));
    }

    /**
     * 渲染DataGrid的表格展示，支持排序和搜索
     */
    protected void renderEasyUIDataGrid(final Page<Record> paginate) {
        Preconditions.checkNotNull(paginate, "参数不能为空");
        renderJson(EuiDataGrid.rsp(paginate));
    }

    /**
     * 渲染DataGrid的表格展示，支持排序和搜索
     *
     * @param sqlGroupName 指定SQL管理的GroupName
     */
    protected void renderEasyUIDataGrid(String sqlGroupName) {
        Preconditions.checkNotNull(sqlGroupName, "sql Group Name 不能为空");
        final Optional<DataGridReq> reqOptional = EuiDataGrid.req(getRequest());
        if (reqOptional.isPresent()) {
            renderJson(EuiDataGrid.rsp(reqOptional.get(), sqlGroupName));
        } else {
            renderJson(EuiDataGrid.EMPTY_DATAGRID);
        }
    }

    /**
     * 渲染DataGrid的表格展示，支持排序和搜索
     *
     * @param sqlGroupName 指定SQL管理的GroupName
     */
    protected void renderEasyUIDataGrid(String sqlGroupName, List<Object> params) {
        Preconditions.checkNotNull(sqlGroupName, "sql Group Name 不能为空");
        final Optional<DataGridReq> reqOptional = EuiDataGrid.req(getRequest());
        if (reqOptional.isPresent()) {
            renderJson(EuiDataGrid.rsp(reqOptional.get(), sqlGroupName, params));
        } else {
            renderJson(EuiDataGrid.EMPTY_DATAGRID);
        }
    }

    /**
     * For information on the logged in user.
 This access is through the way the Cookie and
     * Sessionw
     *
     * @param <M> Generic parameter.
     * @return user model.
     */
    protected <M extends Model> Optional<M> getLogin() {
        final HttpServletRequest request = getRequest();
        if (SecurityKit.isLogin(request)) {
            final M user = SecurityKit.getLoginUser(request);
            return Optional.of(user);
        } else {
            return Optional.absent();
        }
    }

    /**
     * The current Shiro login user.
 If it opens the secruity function can call this method to
     * obtain the logged in user.
     *
     * @param  Generic parameter.
     * @return Shiro login user.
     */
    protected  Optional<AppUser> getPrincipal() {
        if (Securitys.isLogin()) {
            final AppUser appUser = Securitys.getLogin();
            return Optional.of(appUser);
        }
        return Optional.absent();
    }

    /**
     * To get custom paging object.
     *
     * @return To get custom paging object
     */
    protected PageDto getQueryPage() {
        return PageDto.create(this);
    }

    /**
     * JodaTime time request
     *
     * @param name param. the datetime format : yyyy-MM-dd
     * @return datetime.
     */
    protected DateTime getDate(String name) {
        return getDate(name, DateTime.now());
    }

    /**
     * JodaTime time request
     *
     * @param name         param. the datetime format : yyyy-MM-dd
     * @param defaultValue the default value.
     * @return datetime.
     */
    protected DateTime getDate(String name, DateTime defaultValue) {
        String value = getRequest().getParameter(name);
        if (Strings.isNullOrEmpty(value)) {
            return defaultValue;
        }
        return DateKit.parseDashYMDDateTime(value);
    }

    /**
     * JodaTime time request
     *
     * @param name param. the datetime format : yyyy-MM-dd HH:mm:ss
     * @return datetime.
     */
    protected DateTime getDateTime(String name) {
        return getDateTime(name, DateTime.now());
    }

    /**
     * JodaTime time request
     *
     * @param name         param. the datetime format : yyyy-MM-dd HH:mm:ss
     * @param defaultValue the default value.
     * @return datetime.
     */
    protected DateTime getDateTime(String name, DateTime defaultValue) {
        String value = getRequest().getParameter(name);
        if (Strings.isNullOrEmpty(value)) {
            return defaultValue;
        }
        return DateKit.parseDashYMDHMSDateTime(value);
    }

    protected <R> void renderAjaxSiple(AjaxSimple<R> ajaxSimple) {
        renderJson(ajaxSimple);
    }

}


package io.github.oliviercailloux.swt_tools;

import java.util.List;

import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ComboBoxViewerCellEditor;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ImmutableList;

/**
 *

 * An editing support with typed elements and values, using a
 * {@link ComboBoxViewerCellEditor} underlying cell editor. Objects of this type
 * convert elements from the untyped (Object) elements, given by the underlying
 * column viewer, to elements of type E. Similarly, objects of this type convert
 * values from the untyped (Object) values given by the underlying cell editor
 * to values of type V. Both conversions are done using a cast.
 *

 *

 * The user of this class must ensure that the underlying column viewer always
 * gives elements of type E. The underlying column viewer is set at construction
 * time.
 *

 *

 * Objects of this type ensure that the underlying combo box cell editor rejects
 * values out of the provided list of items, thus, the end-user may not type
 * into the combo box a value of its choice that would not belong to the
 * pre-defined list of acceptable choices.
 *

 *

 * The user must go through this object to change the validator
 * behavior of the underlying cell editor. The user may not set or
 * remove the validator directly on the underlying cell editor, and may not
 * change the first-level validator.
 *

 *

 * The user of this class must override {@link #getValueTyped(Object)
 * #getValueTyped(E)} to provide values corresponding to elements; and
 * {@link #setValueTyped(Object, Object) #setValueTyped(E, V)} to set the values
 * sent by the cell editor back to the model. The user may also override
 * {@link #canEditTyped(Object) #canEditTyped(E)} (true by
 * default), and {@link #toString(Object) #toString(V)} (which by default
 * returns the empty string if the value is null, and otherwise
 * uses {@link Object#toString()}). The latter is used to show the entries in
 * the combo box to the end-user.
 *

 *
 * @author Olivier Cailloux
 *
 * @param <E>
 *            the type of elements returned by the underlying column viewer.
 * @param <V>
 *            the type of values to use with the underlying
 *            {@link ComboBoxViewerCellEditor}.
 */
public abstract class ComboBoxEditingSupport<E, V> extends TypedEditingSupportConstantEditor<E, V> {
	@SuppressWarnings("unused")
	static final Logger LOGGER = LoggerFactory.getLogger(ComboBoxEditingSupport.class);

	private List<V> items;

	/**
	 * @param viewer
	 *            must have a composite as underlying control.
	 */
	public ComboBoxEditingSupport(ColumnViewer viewer, Class<E> classOfElements, Class<V> classOfValues) {
		super(viewer, classOfElements, classOfValues);
		setCellEditor(new ComboBoxViewerCellEditor((Composite) viewer.getControl()));
		/**
		 * We could implement inputChanged on the array content provider to
		 * intercept input.
		 */
		getComboBoxCellEditor().setContentProvider(ArrayContentProvider.getInstance());
		getComboBoxCellEditor().setLabelProvider(new LabelProvider() {
			@Override
			public String getText(Object value) {
				final V typedValue = getTypedValue(value);
				return ComboBoxEditingSupport.this.toString(typedValue);
			}
		});
		setFirstLevelValidator(value -> value == null ? "The selection must be one of the provided choices." : null);
		setItems(null);
	}

	@Override
	public CellEditor getCellEditorTyped(E element) {
		return getCellEditor();
	}

	/**
	 * Returns the underlying cell editor. This returns the same object than
	 * {@link #getCellEditorTyped(Object)}, and the same object than
	 * {@link #getCellEditor()}.
	 *
	 * @return not null.
	 */
	public ComboBoxViewerCellEditor getComboBoxCellEditor() {
		return (ComboBoxViewerCellEditor) getCellEditor();
	}

	/**
	 * Only returns the items if they have been set using this object
	 * constructor or {@link #setItems(List)}. If the items have been set (or
	 * modified) directly on the underlying widget, this method has unspecified
	 * effects.
	 *
	 * @return the items, or null if not set.
	 */
	public List<V> getItems() {
		return items;
	}

	/**
	 * Sets the input items to the underlying ComboBoxCellEditor.
	 *
	 * @param items
	 *            a null value is converted to an empty list.
	 */
	public void setItems(List<V> items) {
		final List<V> its = items == null ? ImmutableList.of() : items;
		this.items = its;
		getComboBoxCellEditor().setInput(items);
	}

	public String toString(V value) {
		return value == null ? "" : value.toString();
	}
}


/*
 * Copyright (C) 2011-2013 Eiichiro Uchiumi. All Rights Reserved.
 *
 * Licensed 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.eiichiro.bootleg;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import org.eiichiro.reverb.lang.UncheckedException;

/**
 * {@code Redirect} is a {@link Response} implementation to send a temporary
 * redirect response to the client.
 *
 * @author Eiichiro Uchiumi
 */
public class Redirect implements Response {

	private final String url;

	private String mediaType = "";

	private int status = 0;

	/**
	 * Constructs a new {@code Redirect} instance to redirect to the specified
	 * URL.
	 *
	 * @param url The URL to redirect.
	 */
	public Redirect(String url) {
		this.url = url;
	}

	/**
	 * Sets HTTP response status code.
	 *
	 * @param status HTTP response status code.
	 */
	public void status(int status) {
		if (!(300 <= status && status < 400)) {
			throw new IllegalArgumentException("'status' must not be [" + status + "]");
		}

		this.status = status;
	}

	/**
	 * Sets HTTP response MIME media type.
	 *
	 * @param mediaType HTTP response MIME media type.
	 */
	public void mediaType(String mediaType) {
		if (mediaType == null) {
			throw new IllegalArgumentException("'mediaType' must not be [" + mediaType + "]");
		}

		this.mediaType = mediaType;
	}

	/** Unsupported operation. {@code UnsupportedOperationException} is thrown. */
	public void entity(Object entity) {
		throw new UnsupportedOperationException(
				"'public void entity(Object entity)' is not supoprted in ["
						+ getClass().getName() + "]");
	}

	/**
	 * Writes this HTTP response to the specified Web context.
	 *
	 * @param context Web context.
	 */
	public void to(WebContext context) {
		HttpServletResponse response = context.response();
		if (!mediaType.isEmpty()) {
			response.setHeader("Content-Type", mediaType);
		}

		if (status > 0) {
			response.setStatus(status);
		}

		try {
			response.sendRedirect(response.encodeRedirectURL(url));
		} catch (IOException e) {
			throw new UncheckedException(e);
		}
	}

}


/*
 * Copyright (C) 2011-2013 Eiichiro Uchiumi. All Rights Reserved.
 *
 * Licensed 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.eiichiro.bootleg;

import java.io.IOException;
import java.lang.reflect.Method;

import javax.servlet.http.HttpServletResponse;

import org.eiichiro.bootleg.annotation.Generates;
import org.eiichiro.bootleg.annotation.Negotiated;
import org.eiichiro.reverb.lang.UncheckedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Predicate;

/**
 * HTTP request processing pipeline stage to send Web endpoint invocation
 * result to the client as HTTP response.
 *
 * @author Eiichiro Uchiumi
 */
public class Send implements Predicate<WebContext> {

	private Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * Sends Web endpoint invocation result to the client as HTTP response.
	 * This method processes the response as the following steps:
	 *

	 *
If the Web endpoint invocation result is instance of {@code Response},
	 * sends the HTTP response to the client by invoking {@code Response#to(WebContext)}
	 * method with the current Web context.

	 *
(If it does not so, ) If the Web endpoint method is qualified by
	 * {@code @Generates} annotation, this class determines the {@code Response}
	 * type from the specified MIME media type by invoking
	 * {@code Configuration#responseType(String)}.

	 *
If the Web endpoint method is qualified by {@code @Negotiated}
	 * annotation, this class determines the {@code Response} type from the MIME
	 * media type specified on "Accept" HTTP request header by invoking
	 * {@code Configuration#responseType(String)}.

	 *
(If it does not so, ) If the Web endpoint method is qualified neither
	 * by {@code @Generates} nor {@code @Negotiated} annotation, this class
	 * determines the {@code Response} type by invoking
	 * {@code Configuration#responseType(String)} with empty string.

	 *
Constructs {@code Response} instance and sets the MIME media type and
	 * Web endpoint invocation result, then sends the HTTP response to the
	 * client by invoking {@code Response#to(WebContext)} method with the
	 * current Web context.

	 *

	 *
	 * @param context HTTP request processing context.
	 */
	public boolean apply(WebContext context) {
		Object result = context.result();

		if (result instanceof Response) {
			Response response = (Response) result;
			response.to(context);
			return true;
		}

		try {
			Method method = context.method();
			String contentType = "";
			Generates generates = method.getAnnotation(Generates.class);
			Negotiated negotiated = method.getAnnotation(Negotiated.class);

			if (generates != null) {
				logger.debug("Web endpoint ["
						+ method.getDeclaringClass().getName() + "#" + method.getName()
						+ "] is qualified by [" + generates + "]");
				contentType = generates.value();
			} else if (negotiated != null) {
				logger.debug("Web endpoint ["
						+ method.getDeclaringClass().getName() + "#" + method.getName()
						+ "] is qualified by [" + negotiated + "]");
				String header = context.request().getHeader("Accept");

				if (header != null) {
					// TODO: Parse.
					contentType = header;
				}
			}

			logger.debug("MIME media type is [" + contentType + "]");
			Class<? extends Response> responseType = context.configuration().responseTypes().get(contentType);

			if (responseType == null) {
				throw new CannotSendResponseException(
						HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE,
						"Configuration [" + context.configuration().getClass().getName()
								+ "] does not provide a response type corresponding to ["
								+ contentType + "] media type");
			}

			Response response = responseType.newInstance();
			response.mediaType(contentType);
			response.entity(result);
			response.to(context);
			return true;
		} catch (CannotSendResponseException exception) {
			logger.warn("Failed to send HTTP response", exception);

			try {
				context.response().sendError(exception.status());
				return false;
			} catch (IOException e) {
				throw new UncheckedException(e);
			}

		} catch (Exception e) {
			throw new UncheckedException(e);
		}
	}

}


package com.truward.brikar.server.context;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.PropertySource;

import javax.annotation.Nonnull;
import java.math.BigInteger;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;

/**
 * Application context initializer that contains standard logic for initializing application properties.
 *
 *

 * The reason why this class has {@link #PROPERTIES} and complicated code around it including static helper
 * methods is because only strings can be passed on the servlet initialization stage and what we want is to
 * associate {@link PropertySource} with {@link ConfigurableApplicationContext} created on servlet initialization
 * stage.
 *

 *

 * Since these properties should be created *before* initializing servlet context (they contain things like port
 * number, server shutdown timeout and authorization settings) we can't actually initialize them along with the
 * context, hence the complexity.
 *

 *
 * @author Alexander Shabanov
 */
public final class StandardWebApplicationContextInitializer
    implements ApplicationContextInitializer<ConfigurableApplicationContext> {

  private static final ConcurrentHashMap<String, PropertySource<?>> PROPERTIES = new ConcurrentHashMap<>();

  /**
   * Property which will be known to
   */
  private static final String PROPERTY_SOURCE_SERVLET_CONFIG_KEY = "brikarPropertySource";

  /**
   * Callback interface that caller supposed to support. Implementation is as simple as just calling
   * ServletContext.setInitParameter. The reason why complex callback schema is used here is because standard
   * {@link javax.servlet.ServletContext} is not available at the moment of jetty context initialization however
   * jetty-specific initialization works.
   *

   * So, in order to make this implementation to be container-agnostic (Tomcat, Jetty, Resin) we don't have
   * anything specific to jetty here.
   *

   */
  public interface ServletInitializer {
    void setInitParameter(@Nonnull String key, @Nonnull String value);
  }

  /**
   * Encapsulates the logic for associating property source with a given servlet.
   *
   * @param servletInitializer A callback that encapsulates the call to the container specific way to set init parameter
   * @param source Property source, that needs to be registered and later available to the spring context
   * @return A closeable instance that should be closed to perform cleanup once server is stopped
   */
  @Nonnull
  public static AutoCloseable register(@Nonnull ServletInitializer servletInitializer,
                                       @Nonnull PropertySource<?> source) {
    final BigInteger bigInteger = new BigInteger(64, ThreadLocalRandom.current());
    final String key = bigInteger.toString(16);

    if (PROPERTIES.containsKey(key)) {
      return register(servletInitializer, source); // shouldn't happen
    }

    // associate this key with the context parameter
    servletInitializer.setInitParameter(PROPERTY_SOURCE_SERVLET_CONFIG_KEY, key);
    // ... and put it to the globally visible properties map
    PROPERTIES.put(key, source);

    return new AutoCloseable() {
      @Override
      public void close() {
        PROPERTIES.remove(key);
      }
    };
  }

  @Override
  public void initialize(ConfigurableApplicationContext applicationContext) {
    // get property from the app environment - it should automatically result in ServletContext scanning
    final String key = applicationContext.getEnvironment()
        .getProperty(StandardWebApplicationContextInitializer.PROPERTY_SOURCE_SERVLET_CONFIG_KEY);
    if (key == null) {
      throw new IllegalStateException("There is no property source key associated with " +
          PROPERTY_SOURCE_SERVLET_CONFIG_KEY + " in current ServletConfig");
    }

    final PropertySource<?> propertySource = PROPERTIES.get(key);
    if (propertySource == null) {
      throw new IllegalStateException("There is no resource associated with a key=" + key);
    }

    applicationContext.getEnvironment().getPropertySources().addFirst(propertySource);
  }
}


/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2013-2014 sagyf Yang. The Four Group.
 */

package goja.core.encry;

import goja.core.StringPool;
import goja.core.kits.lang.ExceptionKit;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringEscapeUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * <p> . </p>
 *
 * @author walter yang
 * @version 1.0 2013-10-30 10:53 AM
 * @since JDK 1.5
 */
public class EncodeKit {

    /**
     * sha-算法名称
     */
    public static final  String HASH_ALGORITHM   = "SHA-1";
    /**
     * 计算次数
     */
    public static final  int    HASH_INTERATIONS = 1024;
    /**
     * 长度
     */
    public static final  int    SALT_SIZE        = 8;
    private static final char[] BASE62           =
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();

    /**
     * Hex编码.
     */
    public static String encodeHex(byte[] input) {
        return Hex.encodeHexString(input);
    }

    /**
     * Hex解码.
     */
    public static byte[] decodeHex(String input) {
        try {
            return Hex.decodeHex(input.toCharArray());
        } catch (DecoderException e) {
            throw ExceptionKit.unchecked(e);
        }
    }

    /**
     * Base64编码.
     */
    public static String encodeBase64(byte[] input) {
        return Base64.encodeBase64String(input);
    }

    /**
     * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548).
     */
    public static String encodeUrlSafeBase64(byte[] input) {
        return Base64.encodeBase64URLSafeString(input);
    }

    /**
     * Base64解码.
     */
    public static byte[] decodeBase64(String input) {
        return Base64.decodeBase64(input);
    }

    /**
     * Base62编码。
     */
    public static String encodeBase62(byte[] input) {
        char[] chars = new char[input.length];
        for (int i = 0; i < input.length; i++) {
            chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)];
        }
        return new String(chars);
    }

    /**
     * Html 转码.
     */
    public static String escapeHtml(String html) {
        return StringEscapeUtils.escapeHtml4(html);
    }

    /**
     * Html 解码.
     */
    public static String unescapeHtml(String htmlEscaped) {
        return StringEscapeUtils.unescapeHtml4(htmlEscaped);
    }

    /**
     * Xml 转码.
     */
    public static String escapeXml(String xml) {
        return StringEscapeUtils.escapeXml11(xml);
    }

    /**
     * Xml 解码.
     */
    public static String unescapeXml(String xmlEscaped) {
        return StringEscapeUtils.unescapeXml(xmlEscaped);
    }

    /**
     * URL 编码, Encode默认为UTF-8.
     */
    public static String urlEncode(String part) {
        try {
            return URLEncoder.encode(part, StringPool.UTF_8);
        } catch (UnsupportedEncodingException e) {
            throw ExceptionKit.unchecked(e);
        }
    }

    /**
     * URL 解码, Encode默认为UTF-8.
     */
    public static String urlDecode(String part) {

        try {
            return URLDecoder.decode(part, StringPool.UTF_8);
        } catch (UnsupportedEncodingException e) {
            throw ExceptionKit.unchecked(e);
        }
    }
}


/*
 * Copyright 2010-2013, CloudBees Inc.
 *
 * Licensed 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 com.cloudbees.sdk.extensibility;

import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

/**
 * A component you can inject (via JIT binding) to discover the list of
 * extension points registered via {@link ExtensionFinder}.
 *
 * <pre>
 * @Inject
 * ExtensionList<Foo> foos;
 *
 * void someFunction(){
 *     for (Foo f : foos) {
 *         ...
 *     }
 * }
 * </pre>
 * @author Kohsuke Kawaguchi
 */
@Singleton
public class ExtensionList<T> implements Iterable<T> {
    private final TypeLiteral<T> type;

    @Inject
    private Injector injector;

    // TODO: if we can inject this like we inject Logger, then
    // we don't need to take injector as a parameter

    @Inject
    public ExtensionList(TypeLiteral<T> type) {
        this.type = type;
    }

    public ExtensionList(Class<T> type) {
        this(TypeLiteral.get(type));
    }

    /**
     * If {@link ExtensionList} is injected, then it can be used as
     * {@link Iterable} to list up extensions that are found in that injector.
     */
    public Iterator<T> iterator() {
        if (injector==null)
            throw new IllegalArgumentException();
        return list(injector).iterator();
    }

    /**
     * Returns all the extension implementations in the specified injector.
     */
    public List<T> list(Injector injector) {
        List<T> r = new ArrayList<T>();

        for (Injector i= injector; i!=null; i=i.getParent()) {
            for (Entry<Key<?>, Binding<?>> e : i.getBindings().entrySet()) {
                if (e.getKey().getTypeLiteral().equals(type))
                    r.add((T)e.getValue().getProvider().get());
            }
        }
        return r;
    }
}


/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2013-2014 sagyf Yang. The Four Group.
 */

package goja.core.kits.lang;

/**
 * Runtime utilities.
 */
public class RuntimeKit {

    public static final Runtime RUNTIME = Runtime.getRuntime();

    // ---------------------------------------------------------------- execution

    /**
     * Returns current method signature.
     */
    public static String currentMethod() {
        StackTraceElement[] ste = new Exception().getStackTrace();
        int ndx = (ste.length > 1) ? 1 : 0;
        return new Exception().getStackTrace()[ndx].toString();
    }

    // ---------------------------------------------------------------- memory

    /**
     * Returns the amount of available memory (free memory plus never allocated memory).
     */
    public static long availableMemory() {
        return RUNTIME.freeMemory() + (RUNTIME.maxMemory() - RUNTIME.totalMemory());
    }

    /**
     * Returns the amount of available memory in percents.
     */
    public static float availableMemoryPercent() {
        return availableMemory() * 100.0f / RUNTIME.maxMemory();
    }

    /**
     * Compacts memory as much as possible by allocating huge memory block
     * and then forcing garbage collection.
     */
    public static void compactMemory() {
        try {
            final byte[][] unused = new byte[128][];
            for (int i = unused.length; i-- != 0; ) {
                unused[i] = new byte[2000000000];
            }
        } catch (OutOfMemoryError ignore) {
        }
        System.gc();
    }

    // ---------------------------------------------------------------- location

    /**
     * Returns location of the class. If class is not in a jar, it's classpath
     * is returned; otherwise the jar location.
     */
    public static String classLocation(Class clazz) {
        return clazz.getProtectionDomain().getCodeSource().getLocation().getPath();
    }

    /**
     * Returns jodd location.
     *
     * @see #classLocation
     */
    public static String joddLocation() {
        return classLocation(RuntimeKit.class);
    }

}


package com.truward.brikar.common.log;

import com.truward.brikar.common.log.metric.Metrics;
import com.truward.brikar.common.log.metric.MetricsCollection;
import com.truward.brikar.common.log.metric.StandardMetricsCollection;
import org.slf4j.Logger;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

/**
 * Common constants for logging.
 * These constants should be used to provide more information in a form of structured records in the log files.
 *

 * Certain arguments should come in a form of {@link org.slf4j.MDC} variables, the others may come in a form of
 * metric entries.
 *

 * The metric entry is a substring in log message with specific format: it should start with a constant
 * {@link #METRIC_ENTRY} and then contain comma+space separated entries where key and value are separated by
 * equals sign.
 *

 * Each log record may contain none or exactly one metric entry which should be the last one in log message.
 * It is completely up to the developer to define semantics behind metric attributes, but general convention is as
 * follows:
 * Metrics may contain:
 *

 *
Operation name

 *
Optional time delta (how much time this operation took, in milliseconds)

 *
Optional flag, that indicates whether or not operation is failed. Absence of this flag indicates that
 *   operation succeeded

 *
Optional integer value that represents a count of something

 *

 *

 * Example of metric entries:
 *

 *
@metric1 op=MeasureUsedToFreeMemRatio, cnt=32 - it may mean, that an operation to measure a ratio
 *   of used to free memory has been attempted and its result is 32%

 *
@metric1 op=UserService.getUserById, tDelta=125 - it may mean, that operation to get user by
 *   ID has been executed and it took 125 milliseconds to complete

 *

 *
 * @author Alexander Shabanov
 */
@ParametersAreNonnullByDefault
public final class LogUtil {
  private LogUtil() {}

  /**
   * A name, under which a request vector is known as one of the logger attributes.
   *

   * Request vector is an identifier that uniquely identifies particular service request, where did it come from,
   * as well as its place in the bigger inter-service call graph.
   *

   *
   * See also {@link org.slf4j.MDC}.
   * See also {@link com.truward.brikar.common.tracking.TrackingHttpHeaderNames#REQUEST_VECTOR}.
   */
  public static final String REQUEST_VECTOR = "RV";

  private static final ThreadLocal<MetricsCollection> METRICS_COLLECTION = new ThreadLocal<>();

  /**
   * Maximum size of request vector.
   */
  public static final int MAX_REQUEST_VECTOR_LENGTH = 4096;

  @Nullable
  public static MetricsCollection getLocalMetricsCollection() {
    return METRICS_COLLECTION.get();
  }

  public static MetricsCollection getOrCreateLocalMetricsCollection() {
    MetricsCollection result = getLocalMetricsCollection();
    if (result == null) {
      result = new StandardMetricsCollection();
      setLocalMetricsCollection(result);
    }
    return result;
  }

  public static void setLocalMetricsCollection(@Nullable MetricsCollection value) {
    METRICS_COLLECTION.set(value);
  }

  public static void logInfo(Metrics metrics, Logger log) {
    final MetricsCollection metricsCollection = new StandardMetricsCollection();
    metricsCollection.add(metrics);
    log.info(metricsCollection.toString());
  }

  public static void logInfo(MetricsCollection metricsCollection, Logger log) {
    log.info(metricsCollection.toString());
  }

  public static void logAndResetLocalMetricsCollection(Logger log, @Nullable MetricsCollection newMetricsCollection) {
    final MetricsCollection metricsCollection = getLocalMetricsCollection();
    if (metricsCollection != null) {
      logInfo(metricsCollection, log);
    }
    setLocalMetricsCollection(newMetricsCollection);
  }

  public static void logAndResetLocalMetricsCollection(Logger log) {
    logAndResetLocalMetricsCollection(log, null);
  }

  /**
   * Propagates metrics entry to the local metrics collection or (if unavailable) logs immediately
   *
   * @param metrics Metrics object to log
   * @param log Target logger to use if local metrics collection is not available
   */
  public static void propagateOrLogInfo(Metrics metrics, Logger log) {
    final MetricsCollection metricsCollection = propagate(metrics);
    if (metricsCollection == null) {
      logInfo(metrics, log);
    }
  }

  /**
   * Propagates metrics entry to the thread local metrics collection, does nothing if local metrics collection
   * is missing.
   *
   * @param metrics Metrics to capture
   * @return Local metrics collection or null
   */
  @Nullable
  public static MetricsCollection propagate(Metrics metrics) {
    final MetricsCollection metricsCollection = getLocalMetricsCollection();
    if (metricsCollection != null) {
      metricsCollection.add(metrics);
    }

    return metricsCollection;
  }

  /**
   * Validates, that passed request vector is valid. This function is used to prevent the potential attacker to send
   * garbage request vectors into the service.
   * If passed request vector is invalid, it should be discarded.
   *
   * @param requestVector Request vector to validate
   * @return True, if passed request vector is valid, false otherwise.
   */
  public static boolean isValidRequestVector(@Nullable String requestVector) {
    if (requestVector == null || requestVector.isEmpty() || requestVector.length() > MAX_REQUEST_VECTOR_LENGTH) {
      return false;
    }

    // verify, that each character is within the allowed bounds
    for (int i = 0; i < requestVector.length(); ++i) {
      final char ch = requestVector.charAt(i);
      if (ch <= 32 || ch >= 127) {
        return false;
      }
    }

    return true;
  }

  //
  // Parameters in logging statements.
  //

  /**
   * Preceding keyword, which presence indicates that a special entry will be coded afterwards.
   * There should be one and only one metric entry per logging statement.
   *
   * One identifies record version for possible future extension with the new fields.
   */
  public static final String METRIC_ENTRY = "@metric1";

  /**
   * A name, under which an operation should be known.
   * Usually recorded as one of the metric attributes.
   */
  public static final String OPERATION = "op";

  /**
   * A name, under which an integer count of something, related to the operation should be known.
   * For example, if operation is to measure used/free memory ratio, this field should contain percentage.
   */
  public static final String COUNT = "cnt";

  /**
   * A name of the attribute, corresponding to operation start time (unix time, in milliseconds).
   * Usually recorded as one of the metric attributes.
   */
  public static final String START_TIME = "tStart";

  /**
   * A name of the attribute, corresponding to time spent (in milliseconds).
   * Usually recorded as one of the metric attributes.
   */
  public static final String TIME_DELTA = "tDelta";

  /**
   * A name of an optional attribute which indicates whether or not operation failed.
   * Usually recorded as one of the metric attributes.
   */
  public static final String FAILED = "failed";

  /**
   * HTTP method (invocation type)
   */
  public static final String VERB = "verb";

  /**
   * Http Response Code (integer), e.g. 200 - 'OK', 404 - 'Not Found', etc.
   */
  public static final String RESPONSE_CODE = "responseCode";

  /**
   * Http URL, e.g. /something/like/that
   */
  public static final String URL = "url";

  /**
   * Request vector, that contains in the service call response.
   */
  public static final String RESPONSE_REQUEST_VECTOR = "responseRV";

  /**
   * Value for entry that should be used if corresponding value is omitted.
   */
  public static final String UNKNOWN_VALUE = "?";

  //
  // Helper methods
  //

  /**
   * Encodes a value, so that it won't contain spaces, commas and equal signs.
   *
   * @param value Value to be encoded
   * @return Encoded value or same value if passed argument does not contain whitespace, comma or equals sign
   */
  public static String encodeString(String value) {
    int estimatedSize = 0;
    final int len = value.length();

    // estimate output string size to find out whether encoding is required and avoid reallocations in string builder
    for (int i = 0; i < len; ++i) {
      final char ch = value.charAt(i);
      if (ch <= ' ' || ch == ',') {
        estimatedSize += 3;
        continue;
      }

      ++estimatedSize;
    }

    if (value.length() == estimatedSize) {
      return value; // return value as is - it does not contain any special characters
    }

    final StringBuilder builder = new StringBuilder(estimatedSize);
    for (int i = 0; i < len; ++i) {
      final char ch = value.charAt(i);
      if (ch <= ' ') {
        builder.append("%20");
        continue;
      }

      if (ch == ',') {
        builder.append("%2c");
        continue;
      }

      builder.append(ch);
    }

    return builder.toString();
  }
}


/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2013-2014 sagyf Yang. The Four Group.
 */

package goja.core.kits.lang;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 *

 * .
 *

 *
 * @author walter yang
 * @version 1.0 2013-10-30 10:54 AM
 * @since JDK 1.5
 */
public class ExceptionKit {

    /**
     * 将CheckedException转换为UncheckedException.
     */
    public static RuntimeException unchecked(Exception e) {
        if (e instanceof RuntimeException) {
            return (RuntimeException) e;
        } else {
            return new RuntimeException(e);
        }
    }

    /**
     * 将ErrorStack转化为String.
     */
    public static String getStackTraceAsString(Exception e) {
        StringWriter stringWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stringWriter));
        return stringWriter.toString();
    }

    /**
     * 判断异常是否由某些底层的异常引起.
     */
    public static boolean isCausedBy(Exception ex, Class<? extends Exception>... causeExceptionClasses) {
        Throwable cause = ex.getCause();
        while (cause != null) {
            for (Class<? extends Exception> causeClass : causeExceptionClasses) {
                if (causeClass.isInstance(cause)) {
                    return true;
                }
            }
            cause = cause.getCause();
        }
        return false;
    }

    /**
     * Build a message for the given base message and its cause.
     */
    public static String buildMessage(String message, Throwable cause) {
        if (cause != null) {
            cause = getRootCause(cause);
            StringBuilder buf = new StringBuilder();
            if (message != null) {
                buf.append(message).append("; ");
            }
            buf.append("<--- ").append(cause);
            return buf.toString();
        } else {
            return message;
        }
    }

    /**
     * Introspects the Throwable to obtain the root cause.
     *

     * This method walks through the exception chain to the last element,
     * "root" of the tree, and returns that exception. If no root cause found
     * returns provided throwable.
     */
    public static Throwable getRootCause(Throwable throwable) {
        Throwable cause = throwable.getCause();
        if (cause == null) {
            return throwable;
        }
        throwable = cause;
        while ((throwable = throwable.getCause()) != null) {
            cause = throwable;
        }
        return cause;
    }

}