001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2017-2018 microBean.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
014 * implied.  See the License for the specific language governing
015 * permissions and limitations under the License.
016 */
017package org.microbean.helm.maven;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.List;
022import java.util.Objects;
023
024import java.util.concurrent.Callable;
025import java.util.concurrent.Future;
026
027import hapi.services.tiller.Tiller.GetReleaseStatusRequest;
028import hapi.services.tiller.Tiller.GetReleaseStatusResponse;
029
030import org.apache.maven.plugin.logging.Log;
031
032import org.apache.maven.plugins.annotations.Mojo;
033import org.apache.maven.plugins.annotations.Parameter;
034
035import org.microbean.helm.ReleaseManager;
036
037/**
038 * Retrieves the status of a release version.
039 *
040 * @author <a href="https://about.me/lairdnelson"
041 * target="_parent">Laird Nelson</a>
042 */
043@Mojo(name = "status")
044public class GetReleaseStatusMojo extends AbstractSingleVersionedReleaseMojo {
045
046
047  /*
048   * Instance fields.
049   */
050  
051
052  /**
053   * A {@link List} of <a
054   * href="apidocs/org/microbean/helm/maven/ReleaseStatusListener.html">{@code
055   * ReleaseStatusListener}</a>s whose elements will be notified of
056   * the status retrieval.
057   */
058  @Parameter(alias = "releaseStatusListenersList")
059  private List<ReleaseStatusListener> releaseStatusListeners;
060  
061
062  /*
063   * Constructors.
064   */
065  
066
067  /**
068   * Creates a new {@link GetReleaseStatusMojo}.
069   */
070  public GetReleaseStatusMojo() {
071    super();
072  }
073
074
075  /*
076   * Protected instance methods.
077   */
078  
079
080  /**
081   * {@inheritDoc}
082   *
083   * <p>This implementation retrieves the status for a {@linkplain
084   * #getReleaseName() given release} at a {@linkplain #getVersion()
085   * particular version} and {@linkplain
086   * ReleaseStatusListener#releaseStatusRetrieved(ReleaseStatusEvent)
087   * notifies} registered {@link ReleaseStatusListener}s.</p>
088   */
089  @Override
090  protected void execute(final Callable<ReleaseManager> releaseManagerCallable) throws Exception {
091    Objects.requireNonNull(releaseManagerCallable);
092    final Log log = this.getLog();
093    assert log != null;
094
095    final Integer version = this.getVersion();
096    if (version == null) {
097      throw new IllegalStateException("version was not specified");
098    }
099    
100    final Collection<? extends ReleaseStatusListener> listeners = this.getReleaseStatusListenersList();
101    if (listeners == null || listeners.isEmpty()) {
102      if (log.isInfoEnabled()) {
103        log.info("Skipping execution because there are no ReleaseStatusListeners specified.");
104      }
105      return;
106    }
107    
108    final GetReleaseStatusRequest.Builder requestBuilder = GetReleaseStatusRequest.newBuilder();
109    assert requestBuilder != null;
110
111    final String releaseName = this.getReleaseName();
112    if (releaseName != null) {
113      requestBuilder.setName(releaseName);
114    }
115
116    requestBuilder.setVersion(version.intValue());
117
118    final ReleaseManager releaseManager = releaseManagerCallable.call();
119    if (releaseManager == null) {
120      throw new IllegalStateException("releaseManagerCallable.call() == null");
121    }
122
123    if (log.isInfoEnabled()) {
124      log.info("Retrieving status for release " + releaseName);
125    }
126    
127    final Future<GetReleaseStatusResponse> getReleaseStatusResponseFuture = releaseManager.getStatus(requestBuilder.build());
128    assert getReleaseStatusResponseFuture != null;
129    final GetReleaseStatusResponse getReleaseStatusResponse = getReleaseStatusResponseFuture.get();
130    assert getReleaseStatusResponse != null;
131
132    final ReleaseStatusEvent event = new ReleaseStatusEvent(this, getReleaseStatusResponse);
133    for (final ReleaseStatusListener listener : listeners) {
134      if (listener != null) {
135        listener.releaseStatusRetrieved(event);
136      }
137    }
138    
139  }
140
141
142  /*
143   * Public instance methods.
144   */
145
146  
147  /**
148   * Adds a {@link ReleaseStatusListener} that will be {@linkplain
149   * ReleaseStatusListener#releaseStatusRetrieved(ReleaseStatusEvent)
150   * notified} when a release version's status is retrieved
151   *
152   * @param listener the {@link ReleaseStatusListener} to add; may be
153   * {@code null} in which case no action will be taken
154   *
155   * @see #removeReleaseStatusListener(ReleaseStatusListener)
156   *
157   * @see #getReleaseStatusListenersList()
158   */
159  public void addReleaseStatusListener(final ReleaseStatusListener listener) {
160    if (listener != null) {
161      if (this.releaseStatusListeners == null) {
162        this.releaseStatusListeners = new ArrayList<>();      
163      }
164      this.releaseStatusListeners.add(listener);
165    }
166  }
167
168  /**
169   * Removes a {@link ReleaseStatusListener} from this {@link
170   * GetReleaseStatusMojo}.
171   *
172   * @param listener the {@link ReleaseStatusListener} to remove; may
173   * be {@code null} in which case no action will be taken
174   *
175   * @see #addReleaseStatusListener(ReleaseStatusListener)
176   *
177   * @see #getReleaseStatusListenersList()
178   */
179  public void removeReleaseStatusListener(final ReleaseStatusListener listener) {
180    if (listener != null && this.releaseStatusListeners != null) {
181      this.releaseStatusListeners.remove(listener);
182    }
183  }
184
185  /**
186   * Invokes the {@link #getReleaseStatusListenersList()} method and
187   * {@linkplain Collection#toArray(Object[]) converts its return
188   * value to an array}.
189   *
190   * <p>This method never returns {@code null}.</p>
191   *
192   * <p>Overrides of this method must not return {@code null}.</p>
193   *
194   * @return a non-{@code null} array of {@link
195   * ReleaseStatusListener}s
196   *
197   * @see #getReleaseStatusListenersList()
198   */
199  public ReleaseStatusListener[] getReleaseStatusListeners() {
200    final Collection<ReleaseStatusListener> listeners = this.getReleaseStatusListenersList();
201    if (listeners == null || listeners.isEmpty()) {
202      return new ReleaseStatusListener[0];
203    } else {
204      return listeners.toArray(new ReleaseStatusListener[listeners.size()]);
205    }
206  }
207
208  /**
209   * Returns the {@link List} of {@link ReleaseStatusListener}s whose
210   * elements will be {@linkplain
211   * ReleaseStatusListener#releaseStatusRetrieved(ReleaseStatusEvent)
212   * notified} when a release version's status is retrieved.
213   *
214   * <p>This method may return {@code null}.</p>
215   *
216   * <p>Overrides of this method are permitted to return {@code
217   * null}.</p>
218   *
219   * @return a {@link List} of {@link ReleaseStatusListener}s, or
220   * {@code null}
221   *
222   * @see #setReleaseStatusListenersList(List)
223   *
224   * @see #addReleaseStatusListener(ReleaseStatusListener)
225   *
226   * @see #removeReleaseStatusListener(ReleaseStatusListener)
227   */
228  public List<ReleaseStatusListener> getReleaseStatusListenersList() {
229    return this.releaseStatusListeners;
230  }
231
232  /**
233   * Installs the {@link List} of {@link ReleaseStatusListener}s whose
234   * elements will be {@linkplain
235   * ReleaseStatusListener#releaseStatusRetrieved(ReleaseStatusEvent)
236   * notified when a release version's status is retrieved}.
237   *
238   * @param releaseStatusListeners the {@link List} of {@link
239   * ReleaseStatusListener}s whose elements will be {@linkplain
240   * ReleaseStatusListener#releaseStatusRetrieved(ReleaseStatusEvent)
241   * notified when a release status is retrieved}; may be {@code null}
242   *
243   * @see #getReleaseStatusListenersList()
244   *
245   * @see #addReleaseStatusListener(ReleaseStatusListener)
246   *
247   * @see #removeReleaseStatusListener(ReleaseStatusListener)
248   */
249  public void setReleaseStatusListenersList(final List<ReleaseStatusListener> releaseStatusListeners) {
250    this.releaseStatusListeners = releaseStatusListeners;
251  }
252
253}