package org.sigmah.client.ui.presenter.project.treegrid; /* * #%L * Sigmah * %% * Copyright (C) 2010 - 2016 URD * %% * This program 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 3 of the * License, or (at your option) any later version. * * This program 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import java.util.ArrayList; import java.util.List; import org.sigmah.client.dispatch.CommandResultHandler; import org.sigmah.client.dispatch.DispatchAsync; import org.sigmah.client.dispatch.monitor.LoadingMask; import org.sigmah.client.dispatch.monitor.ProgressMask; import org.sigmah.client.i18n.I18N; import org.sigmah.shared.command.GetProjects; import org.sigmah.shared.command.GetProjectsFromId; import org.sigmah.shared.command.result.ListResult; import org.sigmah.shared.dto.ProjectDTO; import com.allen_sauer.gwt.log.client.Log; import com.extjs.gxt.ui.client.widget.Component; /** * Represents a worker which get projects chunk by chunk. * * @author tmi * @author Denis Colliot (dcolliot@ideia.fr) */ final class GetProjectsWorker { /** * Receives the worker events. * * @author tmi */ public static interface WorkerListener { /** * Method called if a server error occurs. * * @param error * The error. */ void serverError(Throwable error); /** * Method called when a chunk is retrieved. * * @param projects * The chunk. */ void chunkRetrieved(List<ProjectDTO> projects); /** * Method called after the last chunk has been retrieved. */ void ended(); } /** * The dispatcher. */ private final DispatchAsync dispatch; /** * The {@link GetProjects} command to execute. */ private final GetProjects cmd; /** * The component to mask while the worker runs. */ private final Component component; /** * The size of each chunk. */ private final int chunkSize; /** * Listeners. */ private final ArrayList<WorkerListener> listeners; /** * The list of projects ids to retrieve by chunks. */ private List<Integer> projectsIds; /** * The number of projects ids to retrieve by chunks. */ private int projectsIdsSize; /** * The async monitor. */ private ProgressMask monitor; /** * Builds a new worker with a default chuck size to 1. * * @param dispatch * The dispatcher. * @param cmd * The {@link GetProjects} command to execute. */ public GetProjectsWorker(DispatchAsync dispatch, GetProjects cmd, Component component) { this(dispatch, cmd, component, 1); } /** * Builds a new worker. * * @param dispatch * The dispatcher. * @param cmd * The {@link GetProjects} command to execute. * @param component * The component to mask while the worker runs. * @param chunkSize * The size of each chunk. */ public GetProjectsWorker(final DispatchAsync dispatch, final GetProjects cmd, final Component component, final int chunkSize) { assert dispatch != null; assert cmd != null; assert component != null; this.dispatch = dispatch; this.cmd = cmd; this.component = component; this.chunkSize = chunkSize <= 0 ? 1 : chunkSize; this.listeners = new ArrayList<WorkerListener>(); } /** * Adds a listener to this worker. * * @param listener * The new listener. */ public void addWorkerListener(final WorkerListener listener) { this.listeners.add(listener); } /** * Runs the worker. */ public void run() { monitor = new ProgressMask(component, I18N.CONSTANTS.refreshProjectListProjectLoaded()); // First call to get the list of projects ids. cmd.setMappingMode(ProjectDTO.Mode.BASE); dispatch.execute(cmd, new CommandResultHandler<ListResult<ProjectDTO>>() { @Override public void onCommandFailure(final Throwable e) { if (Log.isErrorEnabled()) { Log.error("[GetProjects command] Error while getting projects.", e); } monitor.initCounter(0); fireServerError(e); } @Override public void onCommandSuccess(final ListResult<ProjectDTO> result) { // List of the projects ids. final List<Integer> ids = new ArrayList<Integer>(); for (final ProjectDTO project : result.getList()) { ids.add(project.getId()); } // Retrieves projects by chunks. if (ids != null && !ids.isEmpty()) { projectsIds = ids; projectsIdsSize = ids.size(); monitor.initCounter(projectsIdsSize); chunk(); } else { monitor.initCounter(0); } } }, new LoadingMask(component)); } private void chunk() { // No more project to get. if (projectsIds.isEmpty()) { fireEnded(); return; } // Store the next ids to retrieve. final ArrayList<Integer> nextWaveIds = new ArrayList<Integer>(chunkSize); final int count = projectsIds.size() >= chunkSize ? chunkSize : projectsIds.size(); for (int i = 0; i < count; i++) { nextWaveIds.add(projectsIds.remove(0)); } // Retrieves these projects. dispatch.execute(new GetProjectsFromId(nextWaveIds, ProjectDTO.Mode._USE_PROJECT_MAPPER), new CommandResultHandler<ListResult<ProjectDTO>>() { @Override public void onCommandFailure(final Throwable e) { if (Log.isErrorEnabled()) { Log.error("[GetProjectsFromId command] Error while getting projects.", e); } monitor.increment(projectsIdsSize); fireServerError(e); } @Override public void onCommandSuccess(final ListResult<ProjectDTO> result) { // Updates the monitor. monitor.increment(count); // Fires event. fireChunkRetrieved(result.getList()); // Next chunk. chunk(); } }, monitor); } /** * Method called if a server error occurs. * * @param error * The error. */ protected void fireServerError(final Throwable error) { for (final WorkerListener listener : listeners) { listener.serverError(error); } } /** * Method called when a chunk is retrieved. * * @param projects * The chunk. */ protected void fireChunkRetrieved(final List<ProjectDTO> projects) { for (final WorkerListener listener : listeners) { listener.chunkRetrieved(projects); } } /** * Method called after the last chunk has been retrieved. */ protected void fireEnded() { for (final WorkerListener listener : listeners) { listener.ended(); } } }