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.GetHistoryRequest;
028import hapi.services.tiller.Tiller.GetHistoryResponse;
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 history of a release.
039 *
040 * @author <a href="https://about.me/lairdnelson"
041 * target="_parent">Laird Nelson</a>
042 */
043@Mojo(name = "history")
044public class GetHistoryMojo extends AbstractSingleReleaseMojo {
045
046
047  /*
048   * Instance fields.
049   */
050  
051
052  /**
053   * The maximum number of versions to return.
054   */
055  @Parameter
056  private int max;
057
058  /**
059   * A {@link List} of <a
060   * href="apidocs/org/microbean/helm/maven/ReleaseHistoryListener.html">{@code
061   * ReleaseHistoryListener}</a>s whose elements will be notified of
062   * each item in the history.
063   */
064  @Parameter(alias = "releaseHistoryListenersList")
065  private List<ReleaseHistoryListener> releaseHistoryListeners;
066  
067
068  /*
069   * Constructors.
070   */
071  
072
073  /**
074   * Creates a new {@link GetHistoryMojo}.
075   */
076  public GetHistoryMojo() {
077    super();
078  }
079
080
081  /*
082   * Protected instance methods.
083   */
084  
085
086  /**
087   * {@inheritDoc}
088   *
089   * <p>This implementation retrieves the history for a {@linkplain
090   * #getReleaseName() given release} and {@linkplain
091   * ReleaseHistoryListener#releaseHistoryRetrieved(ReleaseHistoryEvent)
092   * notifies} registered {@link ReleaseHistoryListener}s.</p>
093   */
094  @Override
095  protected void execute(final Callable<ReleaseManager> releaseManagerCallable) throws Exception {
096    Objects.requireNonNull(releaseManagerCallable);
097    final Log log = this.getLog();
098    assert log != null;
099
100    final Collection<? extends ReleaseHistoryListener> listeners = this.getReleaseHistoryListenersList();
101    if (listeners == null || listeners.isEmpty()) {
102      if (log.isInfoEnabled()) {
103        log.info("Skipping execution because there are no ReleaseHistoryListeners specified.");
104      }
105      return;
106    }
107    
108    final GetHistoryRequest.Builder requestBuilder = GetHistoryRequest.newBuilder();
109    assert requestBuilder != null;
110
111    requestBuilder.setMax(this.getMax());
112
113    final String releaseName = this.getReleaseName();
114    if (releaseName != null) {
115      requestBuilder.setName(releaseName);
116    }
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 history for release " + releaseName);
125    }
126    
127    final Future<GetHistoryResponse> getHistoryResponseFuture = releaseManager.getHistory(requestBuilder.build());
128    assert getHistoryResponseFuture != null;
129    final GetHistoryResponse getHistoryResponse = getHistoryResponseFuture.get();
130    assert getHistoryResponse != null;
131
132    final ReleaseHistoryEvent event = new ReleaseHistoryEvent(this, getHistoryResponse);
133    for (final ReleaseHistoryListener listener : listeners) {
134      if (listener != null) {
135        listener.releaseHistoryRetrieved(event);
136      }
137    }
138    
139  }
140
141
142  /*
143   * Public instance methods.
144   */
145
146
147  /**
148   * Returns the maximum number of history entries to retrieve.
149   *
150   * @return the maximum number of history entries to retrieve
151   *
152   * @see #setMax(int)
153   */
154  public int getMax() {
155    return this.max;
156  }
157
158  /**
159   * Sets the maximum number of history entries to retrieve.
160   *
161   * @param max the maximum number of history entries to retrieve
162   *
163   * @see #getMax()
164   */
165  public void setMax(final int max) {
166    this.max = max;
167  }
168
169  /**
170   * Adds a {@link ReleaseHistoryListener} that will be {@linkplain
171   * ReleaseHistoryListener#releaseHistoryRetrieved(ReleaseHistoryEvent)
172   * notified} when a release history is retrieved
173   *
174   * @param listener the {@link ReleaseHistoryListener} to add; may be
175   * {@code null} in which case no action will be taken
176   *
177   * @see #removeReleaseHistoryListener(ReleaseHistoryListener)
178   *
179   * @see #getReleaseHistoryListenersList()
180   */
181  public void addReleaseHistoryListener(final ReleaseHistoryListener listener) {
182    if (listener != null) {
183      if (this.releaseHistoryListeners == null) {
184        this.releaseHistoryListeners = new ArrayList<>();      
185      }
186      this.releaseHistoryListeners.add(listener);
187    }
188  }
189
190  /**
191   * Removes a {@link ReleaseHistoryListener} from this {@link
192   * GetHistoryMojo}.
193   *
194   * @param listener the {@link ReleaseHistoryListener} to remove; may
195   * be {@code null} in which case no action will be taken
196   *
197   * @see #addReleaseHistoryListener(ReleaseHistoryListener)
198   *
199   * @see #getReleaseHistoryListenersList()
200   */
201  public void removeReleaseHistoryListener(final ReleaseHistoryListener listener) {
202    if (listener != null && this.releaseHistoryListeners != null) {
203      this.releaseHistoryListeners.remove(listener);
204    }
205  }
206
207  /**
208   * Invokes the {@link #getReleaseHistoryListenersList()} method and
209   * {@linkplain Collection#toArray(Object[]) converts its return
210   * value to an array}.
211   *
212   * <p>This method never returns {@code null}.</p>
213   *
214   * <p>Overrides of this method must not return {@code null}.</p>
215   *
216   * @return a non-{@code null} array of {@link
217   * ReleaseHistoryListener}s
218   *
219   * @see #getReleaseHistoryListenersList()
220   */
221  public ReleaseHistoryListener[] getReleaseHistoryListeners() {
222    final Collection<ReleaseHistoryListener> listeners = this.getReleaseHistoryListenersList();
223    if (listeners == null || listeners.isEmpty()) {
224      return new ReleaseHistoryListener[0];
225    } else {
226      return listeners.toArray(new ReleaseHistoryListener[listeners.size()]);
227    }
228  }
229
230  /**
231   * Returns the {@link List} of {@link ReleaseHistoryListener}s whose
232   * elements will be {@linkplain
233   * ReleaseHistoryListener#releaseHistoryRetrieved(ReleaseHistoryEvent)
234   * notified} when a release history is retrieved.
235   *
236   * <p>This method may return {@code null}.</p>
237   *
238   * <p>Overrides of this method are permitted to return {@code
239   * null}.</p>
240   *
241   * @return a {@link List} of {@link ReleaseHistoryListener}s, or
242   * {@code null}
243   *
244   * @see #setReleaseHistoryListenersList(List)
245   *
246   * @see #addReleaseHistoryListener(ReleaseHistoryListener)
247   *
248   * @see #removeReleaseHistoryListener(ReleaseHistoryListener)
249   */
250  public List<ReleaseHistoryListener> getReleaseHistoryListenersList() {
251    return this.releaseHistoryListeners;
252  }
253
254  /**
255   * Installs the {@link List} of {@link ReleaseHistoryListener}s
256   * whose elements will be {@linkplain
257   * ReleaseHistoryListener#releaseHistoryRetrieved(ReleaseHistoryEvent)
258   * notified when a release history is retrieved}.
259   *
260   * @param releaseHistoryListeners the {@link List} of {@link
261   * ReleaseHistoryListener}s whose elements will be {@linkplain
262   * ReleaseHistoryListener#releaseHistoryRetrieved(ReleaseHistoryEvent)
263   * notified when a release history is retrieved}; may be {@code
264   * null}
265   *
266   * @see #getReleaseHistoryListenersList()
267   *
268   * @see #addReleaseHistoryListener(ReleaseHistoryListener)
269   *
270   * @see #removeReleaseHistoryListener(ReleaseHistoryListener)
271   */
272  public void setReleaseHistoryListenersList(final List<ReleaseHistoryListener> releaseHistoryListeners) {
273    this.releaseHistoryListeners = releaseHistoryListeners;
274  }
275
276}