| /* |
| * Copyright 2010 Google 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.google.gwt.sample.expenses.server.domain; |
| |
| import com.google.apphosting.api.DeadlineExceededException; |
| |
| import java.util.logging.Logger; |
| |
| import javax.persistence.Column; |
| import javax.persistence.Entity; |
| import javax.persistence.EntityManager; |
| import javax.persistence.EntityTransaction; |
| import javax.persistence.GeneratedValue; |
| import javax.persistence.GenerationType; |
| import javax.persistence.Id; |
| |
| /** |
| * Stores the current entity counts. |
| */ |
| @Entity |
| public class EntityCounter { |
| |
| private static final Logger log = Logger.getLogger(EntityCounter.class.getName()); |
| |
| private static final int KIND_EMPLOYEE = 0; |
| |
| private static final int KIND_EXPENSE = 1; |
| |
| private static final String[] KIND_NAMES = {"Employee", "Expense", "Report"}; |
| |
| private static final int KIND_REPORT = 2; |
| |
| private static final Long ONE = Long.valueOf(1L); |
| |
| private static final Long ZERO = Long.valueOf(0L); |
| |
| private static final boolean DENSE_IDS = false; |
| |
| public static final EntityManager entityManager() { |
| return EMF.get().createEntityManager(); |
| } |
| |
| public static long getEmployeeCount() { |
| EntityCounter counter = getCounter(); |
| Long l = counter.getNumEmployees(); |
| return l == null ? 0 : l.longValue(); |
| } |
| |
| public static long getExpenseCount() { |
| EntityCounter counter = getCounter(); |
| Long l = counter.getNumExpenses(); |
| return l == null ? 0 : l.longValue(); |
| } |
| |
| public static long getReportCount() { |
| EntityCounter counter = getCounter(); |
| Long l = counter.getNumReports(); |
| return l == null ? 0 : l.longValue(); |
| } |
| |
| public static void reset() { |
| EntityCounter counter = getCounter(); |
| counter.clear(); |
| |
| EntityManager em = entityManager(); |
| try { |
| em.merge(counter); |
| } finally { |
| em.close(); |
| } |
| } |
| |
| public static long updateEmployeeCount() { |
| return update(KIND_EMPLOYEE); |
| } |
| |
| public static long updateExpenseCount() { |
| return update(KIND_EXPENSE); |
| } |
| |
| public static long updateReportCount() { |
| return update(KIND_REPORT); |
| } |
| |
| private static void copy(EntityCounter dest, EntityCounter src) { |
| dest.setId(src.getId()); |
| dest.setMaxCheckedEmployeeId(src.getMaxCheckedEmployeeId()); |
| dest.setMaxCheckedExpenseId(src.getMaxCheckedExpenseId()); |
| dest.setMaxCheckedReportId(src.getMaxCheckedReportId()); |
| dest.setNumEmployees(src.getNumEmployees()); |
| dest.setNumExpenses(src.getNumExpenses()); |
| dest.setNumReports(src.getNumReports()); |
| } |
| |
| private static EntityCounter getCounter() { |
| EntityManager em = entityManager(); |
| try { |
| EntityCounter counter = em.find(EntityCounter.class, 1); |
| if (counter == null) { |
| counter = new EntityCounter(); |
| counter.clear(); |
| em.persist(counter); |
| } |
| return counter; |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } finally { |
| em.close(); |
| } |
| } |
| |
| private static long update(int kind) { |
| EntityManager em = entityManager(); |
| |
| String kindName = KIND_NAMES[kind]; |
| log.info("Updating count for " + kindName); |
| |
| EntityCounter oldCounter = getCounter(); |
| EntityCounter counter = new EntityCounter(); |
| copy(counter, oldCounter); |
| |
| log.info("Starting at getMaxCheckedEmployeeId() = " + counter.getMaxCheckedEmployeeId()); |
| log.info("Starting at getMaxCheckedExpenseId() = " + counter.getMaxCheckedExpenseId()); |
| log.info("Starting at getMaxCheckedReportId() = " + counter.getMaxCheckedReportId()); |
| log.info("Starting at getNumEmployees() = " + counter.getNumEmployees()); |
| log.info("Starting at getNumExpenses() = " + counter.getNumExpenses()); |
| log.info("Starting at getNumReports() = " + counter.getNumReports()); |
| |
| long endTime = System.currentTimeMillis() + 20000; |
| EntityTransaction transaction = em.getTransaction(); |
| transaction.begin(); |
| |
| try { |
| while (System.currentTimeMillis() < endTime) { |
| Long min; |
| switch (kind) { |
| case KIND_EMPLOYEE: |
| min = counter.getMaxCheckedEmployeeId(); |
| break; |
| case KIND_EXPENSE: |
| min = counter.getMaxCheckedExpenseId(); |
| break; |
| case KIND_REPORT: |
| min = counter.getMaxCheckedReportId(); |
| break; |
| default: |
| throw new RuntimeException("kind = " + kind); |
| } |
| long mmin = min == null ? 0L : min.longValue(); |
| long mmax = mmin + 1000; |
| mmin = Math.max(1L, mmin); |
| |
| String query = "select count(o) from " + kindName + " o where id >= " |
| + mmin + " and id < " + mmax; |
| Number count = (Number) em.createQuery(query).getSingleResult(); |
| long value = count.longValue(); |
| if (value == 0 && DENSE_IDS) { |
| log.info("Got 0 results between " + mmin + " and " + mmax); |
| break; |
| } |
| |
| mmin = mmax; |
| min = Long.valueOf(mmin); |
| switch (kind) { |
| case KIND_EMPLOYEE: |
| counter.setMaxCheckedEmployeeId(min); |
| Long emp = counter.getNumEmployees(); |
| long totalEmp = (emp == null) ? value : value + emp.longValue(); |
| counter.setNumEmployees(Long.valueOf(totalEmp)); |
| break; |
| case KIND_EXPENSE: |
| counter.setMaxCheckedExpenseId(min); |
| Long exp = counter.getNumExpenses(); |
| long totalExp = (exp == null) ? value : value + exp.longValue(); |
| counter.setNumExpenses(Long.valueOf(totalExp)); |
| break; |
| case KIND_REPORT: |
| counter.setMaxCheckedReportId(min); |
| Long rep = counter.getNumReports(); |
| long totalRep = (rep == null) ? value : value + rep.longValue(); |
| counter.setNumReports(Long.valueOf(totalRep)); |
| break; |
| default: |
| throw new RuntimeException("kind = " + kind); |
| } |
| } |
| |
| em.merge(counter); |
| transaction.commit(); |
| transaction = null; |
| |
| log.info("Ending at getMaxCheckedEmployeeId() = " + counter.getMaxCheckedEmployeeId()); |
| log.info("Ending at getMaxCheckedExpenseId() = " + counter.getMaxCheckedExpenseId()); |
| log.info("Ending at getMaxCheckedReportId() = " + counter.getMaxCheckedReportId()); |
| log.info("Ending at getNumEmployees() = " + counter.getNumEmployees()); |
| log.info("Ending at getNumExpenses() = " + counter.getNumExpenses()); |
| log.info("Ending at getNumReports() = " + counter.getNumReports()); |
| } catch (DeadlineExceededException e) { |
| if (transaction != null) { |
| transaction.commit(); |
| transaction = null; |
| |
| log.info("Ending at getMaxCheckedEmployeeId() = " + counter.getMaxCheckedEmployeeId()); |
| log.info("Ending at getMaxCheckedExpenseId() = " + counter.getMaxCheckedExpenseId()); |
| log.info("Ending at getMaxCheckedReportId() = " + counter.getMaxCheckedReportId()); |
| log.info("Ending at getNumEmployees() = " + counter.getNumEmployees()); |
| log.info("Ending at getNumExpenses() = " + counter.getNumExpenses()); |
| log.info("Ending at getNumReports() = " + counter.getNumReports()); |
| } |
| } catch (RuntimeException e) { |
| log.warning("Got exception " + e.getMessage()); |
| throw e; |
| } finally { |
| if (transaction != null) { |
| log.warning("Rolling back transaction"); |
| transaction.rollback(); |
| } |
| transaction = null; |
| em.close(); |
| } |
| |
| long total; |
| switch (kind) { |
| case KIND_EMPLOYEE: |
| total = counter.getNumEmployees(); |
| break; |
| case KIND_EXPENSE: |
| total = counter.getNumExpenses(); |
| break; |
| case KIND_REPORT: |
| total = counter.getNumReports(); |
| break; |
| default: |
| throw new RuntimeException("kind = " + kind); |
| } |
| log.info("Returning total = " + total); |
| return total; |
| } |
| |
| @Id |
| @Column(name = "id") |
| @GeneratedValue(strategy = GenerationType.IDENTITY) |
| private Long id; |
| |
| private Long maxCheckedEmployeeId; |
| private Long maxCheckedExpenseId; |
| private Long maxCheckedReportId; |
| private Long numEmployees; |
| private Long numExpenses; |
| private Long numReports; |
| |
| public Long getId() { |
| return id; |
| } |
| |
| public Long getMaxCheckedEmployeeId() { |
| return maxCheckedEmployeeId; |
| } |
| |
| public Long getMaxCheckedExpenseId() { |
| return maxCheckedExpenseId; |
| } |
| |
| public Long getMaxCheckedReportId() { |
| return maxCheckedReportId; |
| } |
| |
| public Long getNumEmployees() { |
| return numEmployees; |
| } |
| |
| public Long getNumExpenses() { |
| return numExpenses; |
| } |
| |
| public Long getNumReports() { |
| return numReports; |
| } |
| |
| public void setId(Long id) { |
| this.id = id; |
| } |
| |
| public void setMaxCheckedEmployeeId(Long maxCheckedEmployeeId) { |
| this.maxCheckedEmployeeId = maxCheckedEmployeeId; |
| } |
| |
| public void setMaxCheckedExpenseId(Long maxCheckedExpenseId) { |
| this.maxCheckedExpenseId = maxCheckedExpenseId; |
| } |
| |
| public void setMaxCheckedReportId(Long maxCheckedReportId) { |
| this.maxCheckedReportId = maxCheckedReportId; |
| } |
| |
| public void setNumEmployees(Long numEmployees) { |
| this.numEmployees = numEmployees; |
| } |
| |
| public void setNumExpenses(Long numExpenses) { |
| this.numExpenses = numExpenses; |
| } |
| |
| public void setNumReports(Long numReports) { |
| this.numReports = numReports; |
| } |
| |
| private void clear() { |
| setId(ONE); |
| setNumEmployees(ZERO); |
| setNumExpenses(ZERO); |
| setNumReports(ZERO); |
| setMaxCheckedEmployeeId(ZERO); |
| setMaxCheckedExpenseId(ZERO); |
| setMaxCheckedReportId(ZERO); |
| } |
| } |