Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.ambari.view.hive.resources.jobs; import org.apache.ambari.view.ViewContext; import org.apache.ambari.view.hive.client.ColumnDescription; import org.apache.ambari.view.hive.client.HiveClientException; import org.apache.ambari.view.hive.client.Cursor; import org.apache.ambari.view.hive.utils.ServiceFormattedException; import org.apache.commons.collections4.map.PassiveExpiringMap; import javax.ws.rs.core.Response; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; /** * Results Pagination Controller * Persists cursors for result sets */ public class ResultsPaginationController { public static final String DEFAULT_SEARCH_ID = "default"; private static Map<String, ResultsPaginationController> viewSingletonObjects = new HashMap<String, ResultsPaginationController>(); public static ResultsPaginationController getInstance(ViewContext context) { if (!viewSingletonObjects.containsKey(context.getInstanceName())) viewSingletonObjects.put(context.getInstanceName(), new ResultsPaginationController()); return viewSingletonObjects.get(context.getInstanceName()); } public ResultsPaginationController() { } private static final long EXPIRING_TIME = 10 * 60 * 1000; // 10 minutes private static final int DEFAULT_FETCH_COUNT = 50; private Map<String, Cursor> resultsCache; public static class CustomTimeToLiveExpirationPolicy extends PassiveExpiringMap.ConstantTimeToLiveExpirationPolicy<String, Cursor> { public CustomTimeToLiveExpirationPolicy(long timeToLiveMillis) { super(timeToLiveMillis); } @Override public long expirationTime(String key, Cursor value) { if (key.startsWith("$")) return -1; //never expire return super.expirationTime(key, value); } } private Map<String, Cursor> getResultsCache() { if (resultsCache == null) { PassiveExpiringMap<String, Cursor> resultsCacheExpiringMap = new PassiveExpiringMap<String, Cursor>( new CustomTimeToLiveExpirationPolicy(EXPIRING_TIME)); resultsCache = Collections.synchronizedMap(resultsCacheExpiringMap); } return resultsCache; } /** * Renew timer of cache entry. * @param key name/id of results request * @return false if entry not found; true if renew was ok */ public boolean keepAlive(String key, String searchId) { if (searchId == null) searchId = DEFAULT_SEARCH_ID; String effectiveKey = key + "?" + searchId; if (!getResultsCache().containsKey(effectiveKey)) return false; Cursor cursor = getResultsCache().get(effectiveKey); getResultsCache().put(effectiveKey, cursor); return true; } private Cursor getResultsSet(String key, Callable<Cursor> makeResultsSet) { if (!getResultsCache().containsKey(key)) { Cursor resultSet = null; try { resultSet = makeResultsSet.call(); } catch (Exception ex) { throw new ServiceFormattedException(ex.getMessage(), ex); } getResultsCache().put(key, resultSet); } return getResultsCache().get(key); } public Response.ResponseBuilder request(String key, String searchId, boolean canExpire, String fromBeginning, Integer count, Callable<Cursor> makeResultsSet) throws HiveClientException { if (searchId == null) searchId = DEFAULT_SEARCH_ID; key = key + "?" + searchId; if (!canExpire) key = "$" + key; if (fromBeginning != null && fromBeginning.equals("true") && getResultsCache().containsKey(key)) getResultsCache().remove(key); Cursor resultSet = getResultsSet(key, makeResultsSet); if (count == null) count = DEFAULT_FETCH_COUNT; ResultsResponse resultsResponse = new ResultsResponse(); resultsResponse.setSchema(resultSet.getSchema()); ArrayList<Object[]> rows = new ArrayList<Object[]>(count); int read = resultSet.readRaw(rows, count); resultsResponse.setRows(rows); resultsResponse.setReadCount(read); resultsResponse.setHasNext(resultSet.hasNext()); // resultsResponse.setSize(resultSet.size()); resultsResponse.setOffset(resultSet.getOffset()); return Response.ok(resultsResponse); } private static class ResultsResponse { private ArrayList<ColumnDescription> schema; private ArrayList<Object[]> rows; private int readCount; private boolean hasNext; private long offset; public void setSchema(ArrayList<ColumnDescription> schema) { this.schema = schema; } public ArrayList<ColumnDescription> getSchema() { return schema; } public void setRows(ArrayList<Object[]> rows) { this.rows = rows; } public ArrayList<Object[]> getRows() { return rows; } public void setReadCount(int readCount) { this.readCount = readCount; } public int getReadCount() { return readCount; } public void setHasNext(boolean hasNext) { this.hasNext = hasNext; } public boolean isHasNext() { return hasNext; } public long getOffset() { return offset; } public void setOffset(long offset) { this.offset = offset; } } }