Package com.google.appengine.library

Source Code of com.google.appengine.library.DataStoreBookDataService

// Copyright 2008 Google Inc. All Rights Reserved.

package com.google.appengine.library;

import static com.google.appengine.api.datastore.FetchOptions.Builder.withLimit;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.SortDirection;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;

/**
* @author kjin@google.com (Kevin Jin)
*/
final class DataStoreBookDataService implements BookDataService {

  private final DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();

  public Iterable<Book> asIterable(String jpqlQuery) {
    return new BookIterable(datastoreService.prepare(new QueryConverter().convertQuery(jpqlQuery))
        .asIterable());
  }

  public Iterable<Book> asIterable(String jpqlQuery, int limit, int offset) {
    FetchOptions fo = withLimit(limit).offset(offset);
    return new BookIterable(datastoreService.prepare(new QueryConverter().convertQuery(jpqlQuery))
        .asIterable(fo));
  }

  public int countEntities(String jpqlQuery) {
    return datastoreService.prepare(new QueryConverter().convertQuery(jpqlQuery)).countEntities();
  }

  public void delete(Book book) {
    datastoreService.delete(((BookWithEntity) book).e.getKey());
  }

  public void put(Book book) {
    final Entity e;
    if (book instanceof BookWithEntity) {
      e = ((BookWithEntity) book).e;
    } else {
      e = new Entity("Book");
    }
    e.setProperty("category", book.getCategory());
    e.setProperty("lastname", book.getLastname());
    e.setProperty("firstname", book.getFirstname());
    e.setProperty("title", book.getTitle());
    e.setProperty("created", book.getCreated());
    e.setProperty("year", book.getYear());
    datastoreService.put(e);
  }

  private static final class BookWithEntity extends Book {
    private final Entity e;

    private BookWithEntity(Entity e) {
      super((String) e.getProperty("category"), (Date) e.getProperty("created"),
            (String) e.getProperty("firstname"), (String) e.getProperty("lastname"),
            (String) e.getProperty("title"), ((Long) e.getProperty("year")).intValue());
      this.e = e;
    }
  }

  private static final class BookIterable implements Iterable<Book> {

    public Iterator<Book> iterator() {
      return new BookIterator(it.iterator());
    }

    private BookIterable(Iterable<Entity> it) {
      super();
      this.it = it;
    }

    private final Iterable<Entity> it;
  }

  private static final class BookIterator implements Iterator<Book> {

    public boolean hasNext() {
      return it.hasNext();
    }

    public Book next() {
      Book book = null;
      final Entity e = it.next();
      if (e != null) {
        book =
            new BookWithEntity(e);
      }
      return book;
    }

    public void remove() {
      it.remove();
    }

    private BookIterator(Iterator<Entity> it) {
      super();
      this.it = it;
    }

    private final Iterator<Entity> it;
  }

  private static final class QueryConverter {
    /**
     * Converts a JPQL string into {@code Query}. Only parses the format output
     * by {@code Library}, e.g. WHERE category='test' AND year>1800 ORDER BY
     * year.
     */
    private Query convertQuery(String jpqlQuery) {
      query = new Query("Book");

      tokenizer = new StringTokenizer(jpqlQuery);
      if (tokenizer.hasMoreTokens()) {
        String lastToken = tokenizer.nextToken();
        if (lastToken.equalsIgnoreCase("WHERE")) {
          do {
            parseFilter();
            if (!tokenizer.hasMoreTokens()) {
              break;
            }
            lastToken = tokenizer.nextToken();
          } while (lastToken.equals("AND"));
        }
        if (lastToken.equals("ORDER")) {
          lastToken = tokenizer.nextToken(); // skip "BY"
          assert lastToken.equals("BY");
          while (parseSort()) {
          }
        }
      }

      return query;
    }

    private boolean parseSort() {
      String propName = tokenizer.nextToken();
      String direction = tokenizer.nextToken();
      boolean moreSort = direction.endsWith(",");
      if (moreSort) {
        direction = direction.substring(0, direction.length() - 1);
      }

      SortDirection sd = null;
      if (direction.equals("ASC")) {
        sd = SortDirection.ASCENDING;
      } else if (direction.equals("DESC")) {
        sd = SortDirection.DESCENDING;
      } else {
        assert false : direction + " is not ASC or DESC";
      }
      query.addSort(propName, sd);
      return moreSort;
    }

    private void parseFilter() {
      String filter = tokenizer.nextToken();
      int opIndex = -1;
      for (String op : OPERATORS) {
        opIndex = filter.indexOf(op);
        if (opIndex != -1) {
          String propName = filter.substring(0, opIndex);
          FilterOperator operator = OPERATOR_MAP.get(op);
          String propValue = filter.substring(opIndex + op.length());
          propValue = parseValue(propValue);

          // special case: year has int value
          if (propName.equals("year")) {
            query.addFilter(propName, operator, Integer.parseInt(propValue));
          } else {
            query.addFilter(propName, operator, propValue);
          }
          break;
        }
      }
      assert opIndex != -1 : filter + "missing comparison operator";
    }

    private String parseValue(String propValue) {
      // not quoted
      if (!propValue.startsWith("'")) {
        return propValue;
      }

      while (!propValue.endsWith("'")) {
        // an incomplete quoted literal
        propValue += " " + tokenizer.nextToken();
      }
      propValue = propValue.substring(1, propValue.length() - 1);
      return propValue;
    }

    private StringTokenizer tokenizer;
    private Query query;

    private static final String[] OPERATORS = {">=", ">", "<=", "<", "="};
    private static final FilterOperator[] OPERATOR_ENUMS =
        {FilterOperator.GREATER_THAN_OR_EQUAL, FilterOperator.GREATER_THAN,
         FilterOperator.LESS_THAN_OR_EQUAL, FilterOperator.LESS_THAN, FilterOperator.EQUAL};

    private static final Map<String, FilterOperator> OPERATOR_MAP =
        new HashMap<String, FilterOperator>();
    static {
      for (int ii = 0; ii < OPERATORS.length; ii++) {
        OPERATOR_MAP.put(OPERATORS[ii], OPERATOR_ENUMS[ii]);
      }
    }
  }

  public void close() {
    // no clean-up needed for DataStore.
  }
}
TOP

Related Classes of com.google.appengine.library.DataStoreBookDataService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.