/* * Copyright © 2015 Cask Data, 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 co.cask.cdap.client; import co.cask.cdap.api.annotation.Beta; import co.cask.cdap.api.schedule.Schedule; import co.cask.cdap.api.schedule.ScheduleSpecification; import co.cask.cdap.client.config.ClientConfig; import co.cask.cdap.client.util.RESTClient; import co.cask.cdap.common.NotFoundException; import co.cask.cdap.common.UnauthenticatedException; import co.cask.cdap.proto.Id; import co.cask.cdap.proto.ScheduledRuntime; import co.cask.cdap.proto.codec.ScheduleSpecificationCodec; import co.cask.common.http.HttpMethod; import co.cask.common.http.HttpResponse; import co.cask.common.http.ObjectResponse; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.io.IOException; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.URL; import java.util.List; import java.util.Map; import javax.inject.Inject; /** * Provides ways to interact with CDAP Schedules. */ @Beta public class ScheduleClient { private static final Gson GSON = new GsonBuilder() .registerTypeAdapter(ScheduleSpecification.class, new ScheduleSpecificationCodec()) .create(); private static final Type MAP_STRING_STRING_TYPE = new TypeToken<Map<String, String>>() { }.getType(); private final RESTClient restClient; private final ClientConfig config; @Inject public ScheduleClient(ClientConfig config, RESTClient restClient) { this.config = config; this.restClient = restClient; } public ScheduleClient(ClientConfig config) { this(config, new RESTClient(config)); } public List<ScheduleSpecification> list(Id.Workflow workflow) throws IOException, UnauthenticatedException, NotFoundException { String path = String.format("apps/%s/workflows/%s/schedules", workflow.getApplicationId(), workflow.getId()); URL url = config.resolveNamespacedURLV3(workflow.getNamespace(), path); HttpResponse response = restClient.execute(HttpMethod.GET, url, config.getAccessToken(), HttpURLConnection.HTTP_NOT_FOUND); if (HttpURLConnection.HTTP_NOT_FOUND == response.getResponseCode()) { throw new NotFoundException(workflow); } ObjectResponse<List<ScheduleSpecification>> objectResponse = ObjectResponse.fromJsonBody( response, new TypeToken<List<ScheduleSpecification>>() { }.getType(), GSON); return objectResponse.getResponseObject(); } /** * Get the next scheduled run time of the program. A program may contain multiple schedules. * This method returns the next scheduled runtimes for all the schedules. This method only takes + into account {@link Schedule}s based on time. For schedules based on data, an empty list will + be returned. * * @param workflow Id of the Workflow for which to fetch next run times. * @return list of Scheduled runtimes for the Workflow. Empty list if there are no schedules. */ public List<ScheduledRuntime> nextRuntimes(Id.Workflow workflow) throws IOException, UnauthenticatedException, NotFoundException { String path = String.format("apps/%s/workflows/%s/nextruntime", workflow.getApplicationId(), workflow.getId()); URL url = config.resolveNamespacedURLV3(workflow.getNamespace(), path); HttpResponse response = restClient.execute(HttpMethod.GET, url, config.getAccessToken(), HttpURLConnection.HTTP_NOT_FOUND); if (HttpURLConnection.HTTP_NOT_FOUND == response.getResponseCode()) { throw new NotFoundException(workflow); } ObjectResponse<List<ScheduledRuntime>> objectResponse = ObjectResponse.fromJsonBody( response, new TypeToken<List<ScheduledRuntime>>() { }.getType(), GSON); return objectResponse.getResponseObject(); } public void suspend(Id.Schedule schedule) throws IOException, UnauthenticatedException, NotFoundException { String path = String.format("apps/%s/schedules/%s/suspend", schedule.getApplication().getId(), schedule.getId()); URL url = config.resolveNamespacedURLV3(schedule.getNamespace(), path); HttpResponse response = restClient.execute(HttpMethod.POST, url, config.getAccessToken(), HttpURLConnection.HTTP_NOT_FOUND); if (HttpURLConnection.HTTP_NOT_FOUND == response.getResponseCode()) { throw new NotFoundException(schedule); } } public void resume(Id.Schedule schedule) throws IOException, UnauthenticatedException, NotFoundException { String path = String.format("apps/%s/schedules/%s/resume", schedule.getApplication().getId(), schedule.getId()); URL url = config.resolveNamespacedURLV3(schedule.getNamespace(), path); HttpResponse response = restClient.execute(HttpMethod.POST, url, config.getAccessToken(), HttpURLConnection.HTTP_NOT_FOUND); if (HttpURLConnection.HTTP_NOT_FOUND == response.getResponseCode()) { throw new NotFoundException(schedule); } } public String getStatus(Id.Schedule schedule) throws IOException, UnauthenticatedException, NotFoundException { String path = String.format("apps/%s/schedules/%s/status", schedule.getApplication().getId(), schedule.getId()); URL url = config.resolveNamespacedURLV3(schedule.getNamespace(), path); HttpResponse response = restClient.execute(HttpMethod.GET, url, config.getAccessToken(), HttpURLConnection.HTTP_NOT_FOUND); if (HttpURLConnection.HTTP_NOT_FOUND == response.getResponseCode()) { throw new NotFoundException(schedule); } Map<String, String> responseObject = ObjectResponse.<Map<String, String>>fromJsonBody(response, MAP_STRING_STRING_TYPE, GSON).getResponseObject(); return responseObject.get("status"); } }