All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.caucho.v5.ramp.vault.MethodParserVault Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
 *
 * This file is part of Baratine(TM)
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Baratine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Baratine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Baratine; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Alex Rojkov
 */

package com.caucho.v5.ramp.vault;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.caucho.v5.inject.type.TypeRef;
import com.caucho.v5.util.L10N;

import io.baratine.service.Api;
import io.baratine.service.Result;

public class MethodParserVault
{
  private final static L10N L = new L10N(MethodParserVault.class);

  private final EntityInfo _entityInfo;
  private final Method _method;
  private final char[] _name;
  private int _parseIndex = 0;

  private String _lexeme;

  private VaultDriverDataImpl _driver;

  public MethodParserVault(VaultDriverDataImpl driver,
                              EntityInfo entityInfo,
                              Method method)
  {
    _driver = driver;
    _entityInfo = entityInfo;
    _method = method;
    _name = method.getName().toCharArray();
    
    if (! Modifier.isAbstract(method.getModifiers())) {
      throw new IllegalStateException(_method.toString());
    }
  }

  public  FindQueryVault parse()
  {
    if (_method.getAnnotation(Sql.class) != null) {
      return parseQuery();
    }

    Token token = scanToken();

    switch (token) {
    case FIND: {
      return parseFind();
    }
    default: {
      //throw new IllegalArgumentException(_method.getName());
      return null;
    }
    }
  }

  public  FindQueryVault parseQuery()
  {
    Sql query = _method.getAnnotation(Sql.class);

    Objects.requireNonNull(query);

    String where = query.value();

    return build(where);
  }

  private  FindQueryVault build(String where)
  {
    TypeRef resultType = resultType();
    Class resultClass = (Class) resultType.rawClass();

    FindQueryVault query;

    if (resultClass.isAssignableFrom(ArrayList.class)) {
      query = listResultQuery(where);
    }
    else if (resultClass.equals(_entityInfo.idType())) {
      query = new FindQueryVault.KeyResult(_driver, where);
    }
    else if (Modifier.isAbstract(resultClass.getModifiers())
             || resultClass.isAnnotationPresent(Api.class)) {
      query = new FindQueryVault.ProxyResult(_driver, where, resultClass);
    }
    else {
      query = new FindQueryVault.DataResult(_driver, where, resultClass);
    }

    return query;
  }

  private FindQueryVault listResultQuery(String where)
  {
    FindQueryVault query;

    TypeRef resultType = resultType().param(0);
    Class resultClass = resultType.rawClass();

    if (resultClass.equals(_entityInfo.idType())) {
      query = new FindQueryVault.ListKeyResult(_driver, where);
    }
    else if (Modifier.isAbstract(resultClass.getModifiers())) {
      query = new FindQueryVault.ListProxyResult(_driver, where, resultClass);
    }
    else {
      query = new FindQueryVault.ListDataResult(_driver, where, resultClass);
    }

    return query;
  }

  private FindQueryVault createListResultFieldQuery(FieldInfo field, String where)
  {
    return new FindQueryVault.ListResultField(_driver,
                                             _entityInfo,
                                             field,
                                             where);
  }

  /*
  private FindQueryVault createSingleResultQuery(String where)
  {
    FindQueryVault query = null;

    TypeRef resultType = resultType();

    if (resultType.rawClass().isAssignableFrom(_entityInfo.type())) {
      query = new FindQueryVault.ProxyResult(_driver, where);
    }
    else {
      FieldDesc field = _entityInfo.findFieldByType(resultType);

      query = createSingeResultFieldQuery(field, where);
    }

    return query;
  }

  private FindQueryVault createSingeResultFieldQuery(FieldDesc field,
                                                    String where)
  {
    return new FindQueryVault.SingleFieldResult(_driver,
                                               _entityInfo,
                                               field,
                                               where);
  }
  */

  private TypeRef resultType()
  {
    Type[] parameters = _method.getGenericParameterTypes();

    for (Type parameter : parameters) {
      TypeRef type = TypeRef.of(parameter);

      if (Result.class.equals(type.rawClass())) {
        TypeRef resultTypeRef = type.param(0);

        return resultTypeRef;
      }
    }

    return null;
  }

  private FindQueryVault parseFind()
  {
    Token token = scanToken();

    while (token != Token.BY && token != Token.EOF) {
      token = scanToken();
    }

    String where = null;

    switch (token) {
    case BY: {
      ByExpressionBuilder by = parseBy();

      where = by.getWhere();

      break;
    }
    case EOF: {

      break;
    }
    default: {

    }
    }

    return build(where);
  }

  private ByExpressionBuilder parseBy()
  {
    ByExpressionBuilder by = new ByExpressionBuilder();

    int x = _parseIndex;

    Token token = scanToken();

    if (token == null)
      throw new IllegalStateException(L.l("expected field name at {0} in {1}",
                                          x,
                                          _method.getName()));

    StringBuilder sb = null;

    do {
      switch (token) {
      case IDENTIFIER: {
        if (sb == null)
          sb = new StringBuilder();

        sb.append(_lexeme);

        break;
      }
      case AND: {
        by.setAnd();

        by.addField(fieldTerm(sb.toString()));

        sb = null;

        break;
      }
      case OR: {
        by.setOr();

        by.addField(fieldTerm(sb.toString()));

        sb = null;

        break;
      }
      default: {
        throw new IllegalStateException();
      }
      }
    }
    while ((token = scanToken()) != Token.EOF);

    if (token == Token.EOF) {
      by.addField(fieldTerm(sb.toString()));
    }

    return by;
  }

  private String fieldTerm(String fieldName)
  {
    fieldName = normalize(fieldName);
    
    FieldInfo field = _entityInfo.field(fieldName);

    if (field != null) {
      return field.sqlTerm();
    }
    else {
      throw error("'{0}' is an unknown field in {1}", fieldName, _entityInfo);
    }
  }
  
  private IllegalArgumentException error(String msg, Object ...args)
  {
    return new IllegalArgumentException(L.l(msg, args));
  }

  private Token scanToken()
  {
    int ch = read();

    if (ch == -1)
      return Token.EOF;

    StringBuilder builder = new StringBuilder();

    builder.append((char) ch);

    for (ch = read(); ch > 0 && Character.isLowerCase(ch); ch = read())
      builder.append((char) ch);

    Token token = reserved.get(builder.toString());

    if (token != null) {
      unread();
    }
    else {
      token = Token.IDENTIFIER;
      _lexeme = builder.toString();

      if (ch != -1)
        unread();
    }

    return token;
  }

  int read()
  {
    if (_parseIndex < _name.length) {
      return _name[_parseIndex++];
    }
    else {
      return -1;
    }
  }

  void unread()
  {
    _parseIndex--;
  }

  private static String normalize(String field)
  {
    char ch = field.charAt(0);

    if (Character.isUpperCase(ch)) {
      return "" + Character.toLowerCase(ch) + field.substring(1);
    }
    else {
      return field;
    }
  }

  public static abstract class StoreQueryBuilder
  {
    public abstract FindQueryVault build();
  }

  static class ByExpressionBuilder
  {
    private Mode _mode = Mode.AND;
    private List _fields = new ArrayList<>();
    private String _where = null;

    public void setAnd()
    {
      _mode = Mode.AND;
    }

    public void setOr()
    {
      _mode = Mode.OR;
    }

    public void addField(String field)
    {
      Objects.requireNonNull(field);
      _fields.add(field);
    }

    public String getWhere()
    {
      if (_where == null) {
        StringBuilder where = new StringBuilder(" where ");

        for (int i = 0; i < _fields.size(); i++) {
          String field = normalize(_fields.get(i));

          if (i > 0) {
            where.append(" ").append(_mode).append(" ");
          }

          where.append(field).append("=?");
        }

        return where.toString();
      }

      return _where;
    }

    @Override
    public String toString()
    {
      return ByExpressionBuilder.class.getSimpleName()
             + '['
             + _mode
             + ", "
             + _fields
             + ']';
    }

    enum Mode
    {
      AND,
      OR
    }
  }

  enum Token
  {
    AND("And"),
    BY("By"),
    EOF("eof"),
    FIND("find"),
    IDENTIFIER("identifier"),
    OR("Or"),
    ORDER("OrderBy");

    private String _literal;

    Token(String literal)
    {
      _literal = literal;
    }

    String getLiteral()
    {
      return _literal;
    }
  }

  private final static Map reserved = new HashMap()
  {
    {
      for (Token token : Token.values()) {
        put(token.getLiteral(), token);
      }
    }
  };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy