--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform;
+
+import java.io.File;
+
+/**
+ * Replaces the incomplete {@link org.sonar.api.platform.ServerFileSystem} as many directories can't be
+ * published in API.
+ */
+public interface ServerFileSystem {
+
+ /**
+ * Root directory of the server installation
+ * @return an existing directory
+ */
+ File getHomeDir();
+
+ /**
+ * Temporary directory, clean up on restarts
+ * @return an existing directory
+ */
+ File getTempDir();
+
+ /**
+ * Files of plugins published by web server for scanners
+ * @return a directory which may or not exist
+ */
+ File getDeployedPluginsDir();
+
+ /**
+ * Directory of plugins downloaded through update center. Files
+ * will be moved to {@link #getInstalledPluginsDir()} on startup.
+ * @return a directory which may or not exist
+ */
+ File getDownloadedPluginsDir();
+
+ /**
+ * Directory of currently installed plugins. Used at startup.
+ * @return a directory which may or not exist
+ */
+ File getInstalledPluginsDir();
+
+ /**
+ * The file listing all the installed plugins. Used by scanner only.
+ * @return an existing file
+ * @deprecated see {@link org.sonar.server.startup.GeneratePluginIndex}
+ */
+ @Deprecated
+ File getPluginIndex();
+
+ /**
+ * Directory where plugins to be uninstalled are moved to.
+ * @return a directory which may or not exist
+ */
+ File getUninstalledPluginsDir();
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform;
+
+import java.io.File;
+import org.picocontainer.Startable;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+import static org.sonar.process.ProcessProperties.Property.PATH_DATA;
+import static org.sonar.process.ProcessProperties.Property.PATH_HOME;
+import static org.sonar.process.ProcessProperties.Property.PATH_TEMP;
+
+public class ServerFileSystemImpl implements ServerFileSystem, org.sonar.api.platform.ServerFileSystem, Startable {
+
+ private static final Logger LOGGER = Loggers.get(ServerFileSystemImpl.class);
+
+ private final File homeDir;
+ private final File tempDir;
+ private final File deployDir;
+ private final File uninstallDir;
+
+ public ServerFileSystemImpl(Configuration config) {
+ this.homeDir = new File(config.get(PATH_HOME.getKey()).get());
+ this.tempDir = new File(config.get(PATH_TEMP.getKey()).get());
+ File dataDir = new File(config.get(PATH_DATA.getKey()).get());
+ this.deployDir = new File(dataDir, "web/deploy");
+ this.uninstallDir = new File(getTempDir(), "uninstalled-plugins");
+ }
+
+ @Override
+ public void start() {
+ LOGGER.info("SonarQube home: " + homeDir.getAbsolutePath());
+ }
+
+ @Override
+ public void stop() {
+ // do nothing
+ }
+
+ @Override
+ public File getHomeDir() {
+ return homeDir;
+ }
+
+ @Override
+ public File getTempDir() {
+ return tempDir;
+ }
+
+ @Override
+ public File getDeployedPluginsDir() {
+ return new File(deployDir, "plugins");
+ }
+
+ @Override
+ public File getDownloadedPluginsDir() {
+ return new File(getHomeDir(), "extensions/downloads");
+ }
+
+ @Override
+ public File getInstalledPluginsDir() {
+ return new File(getHomeDir(), "extensions/plugins");
+ }
+
+ @Override
+ public File getPluginIndex() {
+ return new File(deployDir, "plugins/index.txt");
+ }
+
+ @Override
+ public File getUninstalledPluginsDir() {
+ return uninstallDir;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.platform;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.user;
+
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.db.user.GroupDto;
+
+public interface UserSession {
+
+ /**
+ * Login of the authenticated user. Returns {@code null}
+ * if {@link #isLoggedIn()} is {@code false}.
+ */
+ @CheckForNull
+ String getLogin();
+
+ /**
+ * Uuid of the authenticated user. Returns {@code null}
+ * if {@link #isLoggedIn()} is {@code false}.
+ */
+ @CheckForNull
+ String getUuid();
+
+ /**
+ * Name of the authenticated user. Returns {@code null}
+ * if {@link #isLoggedIn()} is {@code false}.
+ */
+ @CheckForNull
+ String getName();
+
+ /**
+ * Database ID of the authenticated user. Returns {@code null}
+ * if {@link #isLoggedIn()} is {@code false}.
+ */
+ @CheckForNull
+ Integer getUserId();
+
+ /**
+ * The groups that the logged-in user is member of. An empty
+ * collection is returned if {@link #isLoggedIn()} is {@code false}.
+ */
+ Collection<GroupDto> getGroups();
+
+ /**
+ * Whether the user is logged-in or anonymous.
+ */
+ boolean isLoggedIn();
+
+ /**
+ * Whether the user has root privileges. If {@code true}, then user automatically
+ * benefits from all the permissions on all organizations and projects.
+ */
+ boolean isRoot();
+
+ /**
+ * Ensures that {@link #isRoot()} returns {@code true} otherwise throws a
+ * {@link org.sonar.server.exceptions.ForbiddenException}.
+ */
+ UserSession checkIsRoot();
+
+ /**
+ * Ensures that user is logged in otherwise throws {@link org.sonar.server.exceptions.UnauthorizedException}.
+ */
+ UserSession checkLoggedIn();
+
+ /**
+ * Returns {@code true} if the permission is granted on the organization, otherwise {@code false}.
+ *
+ * If the organization does not exist, then returns {@code false}.
+ *
+ * Always returns {@code true} if {@link #isRoot()} is {@code true}, even if
+ * organization does not exist.
+ */
+ boolean hasPermission(OrganizationPermission permission, OrganizationDto organization);
+
+ boolean hasPermission(OrganizationPermission permission, String organizationUuid);
+
+ /**
+ * Ensures that {@link #hasPermission(OrganizationPermission, OrganizationDto)} is {@code true},
+ * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
+ */
+ UserSession checkPermission(OrganizationPermission permission, OrganizationDto organization);
+
+ UserSession checkPermission(OrganizationPermission permission, String organizationUuid);
+
+ /**
+ * Returns {@code true} if the permission is granted to user on the component,
+ * otherwise {@code false}.
+ *
+ * If the component does not exist, then returns {@code false}.
+ *
+ * Always returns {@code true} if {@link #isRoot()} is {@code true}, even if
+ * component does not exist.
+ *
+ * If the permission is not granted, then the organization permission is _not_ checked.
+ *
+ * @param component non-null component.
+ * @param permission project permission as defined by {@link org.sonar.core.permission.ProjectPermissions}
+ */
+ boolean hasComponentPermission(String permission, ComponentDto component);
+
+ /**
+ * Using {@link #hasComponentPermission(String, ComponentDto)} is recommended
+ * because it does not have to load project if the referenced component
+ * is not a project.
+ *
+ * @deprecated use {@link #hasComponentPermission(String, ComponentDto)} instead
+ */
+ @Deprecated
+ boolean hasComponentUuidPermission(String permission, String componentUuid);
+
+ /**
+ * Return the subset of specified components which the user has granted permission.
+ * An empty list is returned if input is empty or if no components are allowed to be
+ * accessed.
+ * If the input is ordered, then the returned components are in the same order.
+ * The duplicated components are returned duplicated too.
+ */
+ List<ComponentDto> keepAuthorizedComponents(String permission, Collection<ComponentDto> components);
+
+ /**
+ * Ensures that {@link #hasComponentPermission(String, ComponentDto)} is {@code true},
+ * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
+ */
+ UserSession checkComponentPermission(String projectPermission, ComponentDto component);
+
+ /**
+ * Ensures that {@link #hasComponentUuidPermission(String, String)} is {@code true},
+ * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
+ *
+ * @deprecated use {@link #checkComponentPermission(String, ComponentDto)} instead
+ */
+ @Deprecated
+ UserSession checkComponentUuidPermission(String permission, String componentUuid);
+
+ /**
+ * Whether user can administrate system, for example for using cross-organizations services
+ * like update center, system info or management of users.
+ *
+ * Returns {@code true} if:
+ * <ul>
+ * <li>{@link #isRoot()} is {@code true}</li>
+ * <li>organization feature is disabled and user is administrator of the (single) default organization</li>
+ * </ul>
+ */
+ boolean isSystemAdministrator();
+
+ /**
+ * Ensures that {@link #isSystemAdministrator()} is {@code true},
+ * otherwise throws {@link org.sonar.server.exceptions.ForbiddenException}.
+ */
+ UserSession checkIsSystemAdministrator();
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.user;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.util;
+
+import org.sonar.api.utils.log.Loggers;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static java.lang.String.format;
+
+/**
+ * Abstract implementation of StoppableExecutorService that implements the
+ * stop() method and delegates all methods to the provided ExecutorService instance.
+ */
+public abstract class AbstractStoppableExecutorService<D extends ExecutorService> implements StoppableExecutorService {
+ protected final D delegate;
+
+ public AbstractStoppableExecutorService(D delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void stop() {
+ // Disable new tasks from being submitted
+ delegate.shutdown();
+ try {
+ // Wait a while for existing tasks to terminate
+ if (!delegate.awaitTermination(5, TimeUnit.SECONDS)) {
+ // Cancel currently executing tasks
+ delegate.shutdownNow();
+ // Wait a while for tasks to respond to being canceled
+ if (!delegate.awaitTermination(5, TimeUnit.SECONDS)) {
+ Loggers.get(getClass()).warn(format("Pool %s did not terminate", getClass().getSimpleName()));
+ }
+ }
+ } catch (InterruptedException ie) {
+ Loggers.get(getClass()).warn(format("Termination of pool %s failed", getClass().getSimpleName()), ie);
+ // (Re-)Cancel if current thread also interrupted
+ delegate.shutdownNow();
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ delegate.shutdown();
+ }
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ return delegate.shutdownNow();
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return delegate.isShutdown();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return delegate.isTerminated();
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ return delegate.awaitTermination(timeout, unit);
+ }
+
+ @Override
+ public <T> Future<T> submit(Callable<T> task) {
+ return delegate.submit(task);
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable task, T result) {
+ return delegate.submit(task, result);
+ }
+
+ @Override
+ public Future<?> submit(Runnable task) {
+ return delegate.submit(task);
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
+ return delegate.invokeAll(tasks);
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+ long timeout,
+ TimeUnit unit) throws InterruptedException {
+ return delegate.invokeAll(tasks, timeout, unit);
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
+ return delegate.invokeAny(tasks);
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+ long timeout,
+ TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ return delegate.invokeAny(tasks, timeout, unit);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ delegate.execute(command);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.util;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+public class AbstractStoppableScheduledExecutorServiceImpl<T extends ScheduledExecutorService> extends AbstractStoppableExecutorService<T>
+ implements StoppableScheduledExecutorService {
+ public AbstractStoppableScheduledExecutorServiceImpl(T delegate) {
+ super(delegate);
+ }
+
+ @Override
+ public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+ return delegate.schedule(command, delay, unit);
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+ return delegate.schedule(callable, delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+ return delegate.scheduleAtFixedRate(command, initialDelay, period, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
+ return delegate.scheduleWithFixedDelay(command, initialDelay, delay, unit);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.util;
+
+import java.util.concurrent.ExecutorService;
+
+/**
+ * ExecutorService that exposes a {@code stop} method which can be invoked by Pico container to shutdown properly
+ * the service.
+ */
+public interface StoppableExecutorService extends ExecutorService {
+
+ /**
+ * Stops the ExecutorService nicely (ie. first let a little time for jobs to end and then abort them)
+ */
+ void stop();
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.util;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * ScheduledExecutorService that exposes a {@code stop} method which can be invoked by Pico container to shutdown
+ * properly the service.
+ */
+public interface StoppableScheduledExecutorService extends ScheduledExecutorService, StoppableExecutorService {
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.util;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.util;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AbstractStoppableExecutorServiceTest {
+ private static final Callable<String> SOME_CALLABLE = new Callable<String>() {
+ @Override
+ public String call() {
+ return null;
+ }
+ };
+ private static final Runnable SOME_RUNNABLE = new Runnable() {
+ @Override
+ public void run() {
+
+ }
+ };
+ private static final String SOME_STRING = "some string";
+ private static final long SOME_LONG = 100l;
+ private static final int TIMEOUT = 5;
+ private static final TimeUnit TIMEOUT_UNIT = TimeUnit.SECONDS;
+
+ private ExecutorService executorService = mock(ExecutorService.class);
+ private InOrder inOrder = Mockito.inOrder(executorService);
+ private AbstractStoppableExecutorService underTest = new AbstractStoppableExecutorService(executorService) {
+ };
+ public static final ImmutableList<Callable<String>> CALLABLES = ImmutableList.of(SOME_CALLABLE);
+
+ @Test
+ public void stop_calls_shutdown_and_verify_termination() throws InterruptedException {
+ when(executorService.awaitTermination(TIMEOUT, TIMEOUT_UNIT)).thenReturn(true);
+
+ underTest.stop();
+
+ inOrder.verify(executorService).shutdown();
+ inOrder.verify(executorService).awaitTermination(TIMEOUT, TIMEOUT_UNIT);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void stop_calls_shutdown_then_shutdownNow_if_not_terminated_and_check_termination_again() throws InterruptedException {
+ when(executorService.awaitTermination(TIMEOUT, TIMEOUT_UNIT)).thenReturn(false).thenReturn(true);
+
+ underTest.stop();
+
+ inOrder.verify(executorService).shutdown();
+ inOrder.verify(executorService).awaitTermination(TIMEOUT, TIMEOUT_UNIT);
+ inOrder.verify(executorService).shutdownNow();
+ inOrder.verify(executorService).awaitTermination(TIMEOUT, TIMEOUT_UNIT);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void stop_calls_shutdownnow_if_interrupted_exception_is_raised() throws InterruptedException {
+ when(executorService.awaitTermination(TIMEOUT, TIMEOUT_UNIT)).thenThrow(new InterruptedException());
+
+ underTest.stop();
+
+ inOrder.verify(executorService).shutdown();
+ inOrder.verify(executorService).awaitTermination(TIMEOUT, TIMEOUT_UNIT);
+ inOrder.verify(executorService).shutdownNow();
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void shutdown_delegates_to_executorService() {
+ underTest.shutdown();
+
+ inOrder.verify(executorService).shutdown();
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void shutdownNow_delegates_to_executorService() {
+ underTest.shutdownNow();
+
+ inOrder.verify(executorService).shutdownNow();
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void isShutdown_delegates_to_executorService() {
+ underTest.isShutdown();
+
+ inOrder.verify(executorService).isShutdown();
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void isTerminated_delegates_to_executorService() {
+ underTest.isTerminated();
+
+ inOrder.verify(executorService).isTerminated();
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void awaitTermination_delegates_to_executorService() throws InterruptedException {
+ underTest.awaitTermination(SOME_LONG, SECONDS);
+
+ inOrder.verify(executorService).awaitTermination(SOME_LONG, SECONDS);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void submit_callable_delegates_to_executorService() {
+ underTest.submit(SOME_CALLABLE);
+
+ inOrder.verify(executorService).submit(SOME_CALLABLE);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void submit_runnable_delegates_to_executorService() {
+ underTest.submit(SOME_RUNNABLE);
+
+ inOrder.verify(executorService).submit(SOME_RUNNABLE);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void submit_runnable_with_result_delegates_to_executorService() {
+ underTest.submit(SOME_RUNNABLE, SOME_STRING);
+
+ inOrder.verify(executorService).submit(SOME_RUNNABLE, SOME_STRING);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void invokeAll_delegates_to_executorService() throws InterruptedException {
+ underTest.invokeAll(CALLABLES);
+
+ inOrder.verify(executorService).invokeAll(CALLABLES);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void invokeAll1_delegates_to_executorService() throws InterruptedException {
+ underTest.invokeAll(CALLABLES, SOME_LONG, SECONDS);
+
+ inOrder.verify(executorService).invokeAll(CALLABLES, SOME_LONG, SECONDS);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void invokeAny_delegates_to_executorService() throws ExecutionException, InterruptedException {
+ underTest.invokeAny(CALLABLES);
+
+ inOrder.verify(executorService).invokeAny(CALLABLES);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void invokeAny1_delegates_to_executorService() throws InterruptedException, ExecutionException, TimeoutException {
+ underTest.invokeAny(CALLABLES, SOME_LONG, SECONDS);
+
+ inOrder.verify(executorService).invokeAny(CALLABLES, SOME_LONG, SECONDS);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void execute_delegates_to_executorService() {
+ underTest.execute(SOME_RUNNABLE);
+
+ inOrder.verify(executorService).execute(SOME_RUNNABLE);
+ inOrder.verifyNoMoreInteractions();
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import java.io.File;
-
-/**
- * Replaces the incomplete {@link org.sonar.api.platform.ServerFileSystem} as many directories can't be
- * published in API.
- */
-public interface ServerFileSystem {
-
- /**
- * Root directory of the server installation
- * @return an existing directory
- */
- File getHomeDir();
-
- /**
- * Temporary directory, clean up on restarts
- * @return an existing directory
- */
- File getTempDir();
-
- /**
- * Files of plugins published by web server for scanners
- * @return a directory which may or not exist
- */
- File getDeployedPluginsDir();
-
- /**
- * Directory of plugins downloaded through update center. Files
- * will be moved to {@link #getInstalledPluginsDir()} on startup.
- * @return a directory which may or not exist
- */
- File getDownloadedPluginsDir();
-
- /**
- * Directory of currently installed plugins. Used at startup.
- * @return a directory which may or not exist
- */
- File getInstalledPluginsDir();
-
- /**
- * The file listing all the installed plugins. Used by scanner only.
- * @return an existing file
- * @deprecated see {@link org.sonar.server.startup.GeneratePluginIndex}
- */
- @Deprecated
- File getPluginIndex();
-
- /**
- * Directory where plugins to be uninstalled are moved to.
- * @return a directory which may or not exist
- */
- File getUninstalledPluginsDir();
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform;
-
-import java.io.File;
-import org.picocontainer.Startable;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.server.app.TomcatContexts;
-
-import static org.sonar.process.ProcessProperties.Property.PATH_DATA;
-import static org.sonar.process.ProcessProperties.Property.PATH_HOME;
-import static org.sonar.process.ProcessProperties.Property.PATH_TEMP;
-
-public class ServerFileSystemImpl implements ServerFileSystem, org.sonar.api.platform.ServerFileSystem, Startable {
-
- private static final Logger LOGGER = Loggers.get(ServerFileSystemImpl.class);
-
- private final File homeDir;
- private final File tempDir;
- private final File deployDir;
- private final File uninstallDir;
-
- public ServerFileSystemImpl(Configuration config) {
- this.homeDir = new File(config.get(PATH_HOME.getKey()).get());
- this.tempDir = new File(config.get(PATH_TEMP.getKey()).get());
- File dataDir = new File(config.get(PATH_DATA.getKey()).get());
- this.deployDir = new File(dataDir, TomcatContexts.WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR);
- this.uninstallDir = new File(getTempDir(), "uninstalled-plugins");
- }
-
- @Override
- public void start() {
- LOGGER.info("SonarQube home: " + homeDir.getAbsolutePath());
- }
-
- @Override
- public void stop() {
- // do nothing
- }
-
- @Override
- public File getHomeDir() {
- return homeDir;
- }
-
- @Override
- public File getTempDir() {
- return tempDir;
- }
-
- @Override
- public File getDeployedPluginsDir() {
- return new File(deployDir, "plugins");
- }
-
- @Override
- public File getDownloadedPluginsDir() {
- return new File(getHomeDir(), "extensions/downloads");
- }
-
- @Override
- public File getInstalledPluginsDir() {
- return new File(getHomeDir(), "extensions/plugins");
- }
-
- @Override
- public File getPluginIndex() {
- return new File(deployDir, "plugins/index.txt");
- }
-
- @Override
- public File getUninstalledPluginsDir() {
- return uninstallDir;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.user;
-
-import java.util.Collection;
-import java.util.List;
-import javax.annotation.CheckForNull;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.permission.OrganizationPermission;
-import org.sonar.db.user.GroupDto;
-
-public interface UserSession {
-
- /**
- * Login of the authenticated user. Returns {@code null}
- * if {@link #isLoggedIn()} is {@code false}.
- */
- @CheckForNull
- String getLogin();
-
- /**
- * Uuid of the authenticated user. Returns {@code null}
- * if {@link #isLoggedIn()} is {@code false}.
- */
- @CheckForNull
- String getUuid();
-
- /**
- * Name of the authenticated user. Returns {@code null}
- * if {@link #isLoggedIn()} is {@code false}.
- */
- @CheckForNull
- String getName();
-
- /**
- * Database ID of the authenticated user. Returns {@code null}
- * if {@link #isLoggedIn()} is {@code false}.
- */
- @CheckForNull
- Integer getUserId();
-
- /**
- * The groups that the logged-in user is member of. An empty
- * collection is returned if {@link #isLoggedIn()} is {@code false}.
- */
- Collection<GroupDto> getGroups();
-
- /**
- * Whether the user is logged-in or anonymous.
- */
- boolean isLoggedIn();
-
- /**
- * Whether the user has root privileges. If {@code true}, then user automatically
- * benefits from all the permissions on all organizations and projects.
- */
- boolean isRoot();
-
- /**
- * Ensures that {@link #isRoot()} returns {@code true} otherwise throws a
- * {@link org.sonar.server.exceptions.ForbiddenException}.
- */
- UserSession checkIsRoot();
-
- /**
- * Ensures that user is logged in otherwise throws {@link org.sonar.server.exceptions.UnauthorizedException}.
- */
- UserSession checkLoggedIn();
-
- /**
- * Returns {@code true} if the permission is granted on the organization, otherwise {@code false}.
- *
- * If the organization does not exist, then returns {@code false}.
- *
- * Always returns {@code true} if {@link #isRoot()} is {@code true}, even if
- * organization does not exist.
- */
- boolean hasPermission(OrganizationPermission permission, OrganizationDto organization);
-
- boolean hasPermission(OrganizationPermission permission, String organizationUuid);
-
- /**
- * Ensures that {@link #hasPermission(OrganizationPermission, OrganizationDto)} is {@code true},
- * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
- */
- UserSession checkPermission(OrganizationPermission permission, OrganizationDto organization);
-
- UserSession checkPermission(OrganizationPermission permission, String organizationUuid);
-
- /**
- * Returns {@code true} if the permission is granted to user on the component,
- * otherwise {@code false}.
- *
- * If the component does not exist, then returns {@code false}.
- *
- * Always returns {@code true} if {@link #isRoot()} is {@code true}, even if
- * component does not exist.
- *
- * If the permission is not granted, then the organization permission is _not_ checked.
- *
- * @param component non-null component.
- * @param permission project permission as defined by {@link org.sonar.core.permission.ProjectPermissions}
- */
- boolean hasComponentPermission(String permission, ComponentDto component);
-
- /**
- * Using {@link #hasComponentPermission(String, ComponentDto)} is recommended
- * because it does not have to load project if the referenced component
- * is not a project.
- *
- * @deprecated use {@link #hasComponentPermission(String, ComponentDto)} instead
- */
- @Deprecated
- boolean hasComponentUuidPermission(String permission, String componentUuid);
-
- /**
- * Return the subset of specified components which the user has granted permission.
- * An empty list is returned if input is empty or if no components are allowed to be
- * accessed.
- * If the input is ordered, then the returned components are in the same order.
- * The duplicated components are returned duplicated too.
- */
- List<ComponentDto> keepAuthorizedComponents(String permission, Collection<ComponentDto> components);
-
- /**
- * Ensures that {@link #hasComponentPermission(String, ComponentDto)} is {@code true},
- * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
- */
- UserSession checkComponentPermission(String projectPermission, ComponentDto component);
-
- /**
- * Ensures that {@link #hasComponentUuidPermission(String, String)} is {@code true},
- * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}.
- *
- * @deprecated use {@link #checkComponentPermission(String, ComponentDto)} instead
- */
- @Deprecated
- UserSession checkComponentUuidPermission(String permission, String componentUuid);
-
- /**
- * Whether user can administrate system, for example for using cross-organizations services
- * like update center, system info or management of users.
- *
- * Returns {@code true} if:
- * <ul>
- * <li>{@link #isRoot()} is {@code true}</li>
- * <li>organization feature is disabled and user is administrator of the (single) default organization</li>
- * </ul>
- */
- boolean isSystemAdministrator();
-
- /**
- * Ensures that {@link #isSystemAdministrator()} is {@code true},
- * otherwise throws {@link org.sonar.server.exceptions.ForbiddenException}.
- */
- UserSession checkIsSystemAdministrator();
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.util;
-
-import org.sonar.api.utils.log.Loggers;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import static java.lang.String.format;
-
-/**
- * Abstract implementation of StoppableExecutorService that implements the
- * stop() method and delegates all methods to the provided ExecutorService instance.
- */
-public abstract class AbstractStoppableExecutorService<D extends ExecutorService> implements StoppableExecutorService {
- protected final D delegate;
-
- public AbstractStoppableExecutorService(D delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void stop() {
- // Disable new tasks from being submitted
- delegate.shutdown();
- try {
- // Wait a while for existing tasks to terminate
- if (!delegate.awaitTermination(5, TimeUnit.SECONDS)) {
- // Cancel currently executing tasks
- delegate.shutdownNow();
- // Wait a while for tasks to respond to being canceled
- if (!delegate.awaitTermination(5, TimeUnit.SECONDS)) {
- Loggers.get(getClass()).warn(format("Pool %s did not terminate", getClass().getSimpleName()));
- }
- }
- } catch (InterruptedException ie) {
- Loggers.get(getClass()).warn(format("Termination of pool %s failed", getClass().getSimpleName()), ie);
- // (Re-)Cancel if current thread also interrupted
- delegate.shutdownNow();
- }
- }
-
- @Override
- public void shutdown() {
- delegate.shutdown();
- }
-
- @Override
- public List<Runnable> shutdownNow() {
- return delegate.shutdownNow();
- }
-
- @Override
- public boolean isShutdown() {
- return delegate.isShutdown();
- }
-
- @Override
- public boolean isTerminated() {
- return delegate.isTerminated();
- }
-
- @Override
- public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
- return delegate.awaitTermination(timeout, unit);
- }
-
- @Override
- public <T> Future<T> submit(Callable<T> task) {
- return delegate.submit(task);
- }
-
- @Override
- public <T> Future<T> submit(Runnable task, T result) {
- return delegate.submit(task, result);
- }
-
- @Override
- public Future<?> submit(Runnable task) {
- return delegate.submit(task);
- }
-
- @Override
- public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
- return delegate.invokeAll(tasks);
- }
-
- @Override
- public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
- long timeout,
- TimeUnit unit) throws InterruptedException {
- return delegate.invokeAll(tasks, timeout, unit);
- }
-
- @Override
- public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
- return delegate.invokeAny(tasks);
- }
-
- @Override
- public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
- long timeout,
- TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- return delegate.invokeAny(tasks, timeout, unit);
- }
-
- @Override
- public void execute(Runnable command) {
- delegate.execute(command);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.util;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-public class AbstractStoppableScheduledExecutorServiceImpl<T extends ScheduledExecutorService> extends AbstractStoppableExecutorService<T>
- implements StoppableScheduledExecutorService {
- public AbstractStoppableScheduledExecutorServiceImpl(T delegate) {
- super(delegate);
- }
-
- @Override
- public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
- return delegate.schedule(command, delay, unit);
- }
-
- @Override
- public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
- return delegate.schedule(callable, delay, unit);
- }
-
- @Override
- public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
- return delegate.scheduleAtFixedRate(command, initialDelay, period, unit);
- }
-
- @Override
- public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
- return delegate.scheduleWithFixedDelay(command, initialDelay, delay, unit);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.util;
-
-import java.util.concurrent.ExecutorService;
-
-/**
- * ExecutorService that exposes a {@code stop} method which can be invoked by Pico container to shutdown properly
- * the service.
- */
-public interface StoppableExecutorService extends ExecutorService {
-
- /**
- * Stops the ExecutorService nicely (ie. first let a little time for jobs to end and then abort them)
- */
- void stop();
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.util;
-
-import java.util.concurrent.ScheduledExecutorService;
-
-/**
- * ScheduledExecutorService that exposes a {@code stop} method which can be invoked by Pico container to shutdown
- * properly the service.
- */
-public interface StoppableScheduledExecutorService extends ScheduledExecutorService, StoppableExecutorService {
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.util;
-
-import com.google.common.collect.ImmutableList;
-import org.junit.Test;
-import org.mockito.InOrder;
-import org.mockito.Mockito;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class AbstractStoppableExecutorServiceTest {
- private static final Callable<String> SOME_CALLABLE = new Callable<String>() {
- @Override
- public String call() {
- return null;
- }
- };
- private static final Runnable SOME_RUNNABLE = new Runnable() {
- @Override
- public void run() {
-
- }
- };
- private static final String SOME_STRING = "some string";
- private static final long SOME_LONG = 100l;
- private static final int TIMEOUT = 5;
- private static final TimeUnit TIMEOUT_UNIT = TimeUnit.SECONDS;
-
- private ExecutorService executorService = mock(ExecutorService.class);
- private InOrder inOrder = Mockito.inOrder(executorService);
- private AbstractStoppableExecutorService underTest = new AbstractStoppableExecutorService(executorService) {
- };
- public static final ImmutableList<Callable<String>> CALLABLES = ImmutableList.of(SOME_CALLABLE);
-
- @Test
- public void stop_calls_shutdown_and_verify_termination() throws InterruptedException {
- when(executorService.awaitTermination(TIMEOUT, TIMEOUT_UNIT)).thenReturn(true);
-
- underTest.stop();
-
- inOrder.verify(executorService).shutdown();
- inOrder.verify(executorService).awaitTermination(TIMEOUT, TIMEOUT_UNIT);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void stop_calls_shutdown_then_shutdownNow_if_not_terminated_and_check_termination_again() throws InterruptedException {
- when(executorService.awaitTermination(TIMEOUT, TIMEOUT_UNIT)).thenReturn(false).thenReturn(true);
-
- underTest.stop();
-
- inOrder.verify(executorService).shutdown();
- inOrder.verify(executorService).awaitTermination(TIMEOUT, TIMEOUT_UNIT);
- inOrder.verify(executorService).shutdownNow();
- inOrder.verify(executorService).awaitTermination(TIMEOUT, TIMEOUT_UNIT);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void stop_calls_shutdownnow_if_interrupted_exception_is_raised() throws InterruptedException {
- when(executorService.awaitTermination(TIMEOUT, TIMEOUT_UNIT)).thenThrow(new InterruptedException());
-
- underTest.stop();
-
- inOrder.verify(executorService).shutdown();
- inOrder.verify(executorService).awaitTermination(TIMEOUT, TIMEOUT_UNIT);
- inOrder.verify(executorService).shutdownNow();
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void shutdown_delegates_to_executorService() {
- underTest.shutdown();
-
- inOrder.verify(executorService).shutdown();
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void shutdownNow_delegates_to_executorService() {
- underTest.shutdownNow();
-
- inOrder.verify(executorService).shutdownNow();
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void isShutdown_delegates_to_executorService() {
- underTest.isShutdown();
-
- inOrder.verify(executorService).isShutdown();
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void isTerminated_delegates_to_executorService() {
- underTest.isTerminated();
-
- inOrder.verify(executorService).isTerminated();
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void awaitTermination_delegates_to_executorService() throws InterruptedException {
- underTest.awaitTermination(SOME_LONG, SECONDS);
-
- inOrder.verify(executorService).awaitTermination(SOME_LONG, SECONDS);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void submit_callable_delegates_to_executorService() {
- underTest.submit(SOME_CALLABLE);
-
- inOrder.verify(executorService).submit(SOME_CALLABLE);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void submit_runnable_delegates_to_executorService() {
- underTest.submit(SOME_RUNNABLE);
-
- inOrder.verify(executorService).submit(SOME_RUNNABLE);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void submit_runnable_with_result_delegates_to_executorService() {
- underTest.submit(SOME_RUNNABLE, SOME_STRING);
-
- inOrder.verify(executorService).submit(SOME_RUNNABLE, SOME_STRING);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void invokeAll_delegates_to_executorService() throws InterruptedException {
- underTest.invokeAll(CALLABLES);
-
- inOrder.verify(executorService).invokeAll(CALLABLES);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void invokeAll1_delegates_to_executorService() throws InterruptedException {
- underTest.invokeAll(CALLABLES, SOME_LONG, SECONDS);
-
- inOrder.verify(executorService).invokeAll(CALLABLES, SOME_LONG, SECONDS);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void invokeAny_delegates_to_executorService() throws ExecutionException, InterruptedException {
- underTest.invokeAny(CALLABLES);
-
- inOrder.verify(executorService).invokeAny(CALLABLES);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void invokeAny1_delegates_to_executorService() throws InterruptedException, ExecutionException, TimeoutException {
- underTest.invokeAny(CALLABLES, SOME_LONG, SECONDS);
-
- inOrder.verify(executorService).invokeAny(CALLABLES, SOME_LONG, SECONDS);
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void execute_delegates_to_executorService() {
- underTest.execute(SOME_RUNNABLE);
-
- inOrder.verify(executorService).execute(SOME_RUNNABLE);
- inOrder.verifyNoMoreInteractions();
- }
-}