/* * Copyright 2013 Eediom 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 org.araqne.logdb.client; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * 쿼리 개체의 상태 정보를 표현합니다. * * @author xeraph@eediom.com * */ public class LogQuery { private LogDbClient client; private int id; private String queryString; private String status; private long loadedCount; private boolean background; private int stamp; // @since 0.9.0 private Date startTime; // @since 0.9.0 private Date finishTime; // @since 1.0.0 private Integer errorCode; private String errorDetail; private Long elapsed; private List<LogQueryCommand> commands = new ArrayList<LogQueryCommand>(); private CopyOnWriteArrayList<WaitingCondition> waitingConditions; // @since 0.9.1 private List<SubQuery> subQueries = new ArrayList<SubQuery>(); public LogQuery(LogDbClient client, int id, String queryString) { this.client = client; this.id = id; this.queryString = queryString; this.status = "Stopped"; this.loadedCount = 0; this.waitingConditions = new CopyOnWriteArrayList<WaitingCondition>(); } /** * 쿼리 식별자를 반환합니다. * * @return 쿼리 식별자 */ public int getId() { return id; } /** * 쿼리 상태의 버전을 반환합니다. 숫자가 클수록 최신 정보입니다. 스탬프는 클라이언트와 서버 통신 간에 메시지 전달이 지연될 때 구 * 버전이 새 버전 정보를 덮어쓰는 일을 막는 용도로 사용됩니다. * * @return 스탬프 값 */ public int getStamp() { return stamp; } /** * 쿼리 상태의 버전을 설정합니다. * * @param stamp * 스탬프 값 */ public void setStamp(int stamp) { this.stamp = stamp; } /** * 쿼리 결과가 적재된 건수를 반환합니다. * * @return 쿼리 결과 적재 건수 */ public long getLoadedCount() { return loadedCount; } /** * 쿼리 동작 상태를 반환합니다. Waiting, Running, Stopped, Cancelled, Ended 중 하나의 상태를 * 가집니다. * * @return 쿼리 동작 상태. */ public String getStatus() { return getStatus(false); } /** * 쿼리 동작 상태를 반환합니다. Waiting, Running, Stopped, Cancelled, Ended 중 하나의 상태를 * 가집니다. * * @param refresh * RPC를 통한 쿼리 상태 갱신 여부 * @since 0.8.3 */ public String getStatus(boolean refresh) { if (refresh) { try { // comet client do not support refresh if (client != null) client.getQuery(id); } catch (IOException e) { } } return status; } /** * 쿼리 결과가 지정된 건수 이상 준비될 때까지 스레드 실행을 차단합니다. * * @param count * 대기할 건수, null인 경우 쿼리 종료 시까지 대기 */ public void waitUntil(Long count) { WaitingCondition cond = new WaitingCondition(count); try { waitingConditions.add(cond); synchronized (cond.signal) { try { while (!status.equals("Ended") && !status.equals("Cancelled") && (count == null || loadedCount < count)) cond.signal.wait(100); } catch (InterruptedException e) { } } } finally { waitingConditions.remove(cond); } } /** * 쿼리 결과 적재 건수를 갱신합니다. * * @param count * 쿼리 결과 적재 건수 * @param stamp * 스탬프 버전 */ public void updateCount(long count, long stamp) { if (stamp != 0 && this.stamp >= stamp) return; loadedCount = count; for (WaitingCondition cond : waitingConditions) { if (cond.threshold != null && cond.threshold <= loadedCount) { synchronized (cond.signal) { cond.signal.notifyAll(); } } } } /** * 쿼리 동작 상태를 갱신합니다. * * @param status * 쿼리 동작 상태 * @param stamp * 스탬프 버전 */ public void updateStatus(String status, long stamp) { if (stamp != 0 && this.stamp >= stamp) return; this.status = status; if (status.equals("Ended") || status.equals("Cancelled")) { for (WaitingCondition cond : waitingConditions) { synchronized (cond.signal) { cond.signal.notifyAll(); } } } } /** * 백그라운드 실행 여부를 반환합니다. * * @return 백그라운드 실행 여부 */ public boolean isBackground() { return background; } /** * 백그라운드 실행 여부를 설정합니다. * * @param background * 백그라운드 실행 여부 */ public void setBackground(boolean background) { this.background = background; } /** * 쿼리 시작 시각을 반환합니다. * * @return 쿼리 시작 시각 * @since 0.9.0 */ public Date getStartTime() { return startTime; } /** * 쿼리 시작 시각을 설정합니다. * * @param startTime * 쿼리 시작 시각 * @since 0.9.0 */ public void setStartTime(Date startTime) { this.startTime = startTime; } /** * 쿼리 종료 시각을 반환합니다. * * @return 쿼리 종료 시각 * @since 0.9.0 */ public Date getFinishTime() { return finishTime; } /** * 쿼리 종료 시작을 설정합니다. * * @param finishTime * 쿼리 종료 시각 */ public void setFinishTime(Date finishTime) { this.finishTime = finishTime; } @Deprecated public Date getLastStarted() { return startTime; } @Deprecated public void setLastStarted(Date lastStarted) { this.startTime = lastStarted; } /** * 쿼리 시작 후 경과된 시간을 반환합니다. * * @return 쿼리 시작 후 경과 시간 (밀리초) */ public Long getElapsed() { return elapsed; } /** * 쿼리 시작 후 경과된 시각을 설정합니다. * * @param elapsed * 쿼리 시작 후 경과 시간 (밀리초) */ public void setElapsed(Long elapsed) { this.elapsed = elapsed; } /** * 쿼리를 구성하는 커맨드 목록을 반환합니다. * * @return 쿼리 커맨드 목록 */ public List<LogQueryCommand> getCommands() { return commands; } /** * 쿼리를 구성하는 커맨드 목록을 설정합니다. * * @param commands * 쿼리 커맨드 목록 */ public void setCommands(List<LogQueryCommand> commands) { this.commands = commands; } /** * 서브 쿼리 목록을 반환합니다. * * @return 서브 쿼리 목록 */ public List<SubQuery> getSubQueries() { return subQueries; } /** * 서브 쿼리 목록을 설정합니다. * * @param subQueries * 서브 쿼리 목록 */ public void setSubQueries(List<SubQuery> subQueries) { this.subQueries = subQueries; } public Integer getErrorCode() { return errorCode; } public void setErrorCode(Integer errorCode) { this.errorCode = errorCode; } public String getErrorDetail() { return errorDetail; } public void setErrorDetail(String errorDetail) { this.errorDetail = errorDetail; } private class WaitingCondition { private Long threshold; private Object signal = new Object(); public WaitingCondition(Long threshold) { this.threshold = threshold; } } @Override public String toString() { return "id=" + id + ", query=" + queryString + ", status=" + status + ", loaded=" + loadedCount; } }