Skip to content

Commit

Permalink
#50 - Completing the migration of moving all Plugin related stuff to …
Browse files Browse the repository at this point in the history
…AbstractNotificationPlugin
  • Loading branch information
ashwanthkumar committed Jul 5, 2016
1 parent 9384460 commit aa03d1b
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 99 deletions.
88 changes: 22 additions & 66 deletions src/main/java/in/ashwanthkumar/gocd/slack/GoNotificationPlugin.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,23 @@
package in.ashwanthkumar.gocd.slack;

import com.google.gson.GsonBuilder;
import com.thoughtworks.go.plugin.api.GoApplicationAccessor;
import com.thoughtworks.go.plugin.api.GoPlugin;
import com.thoughtworks.go.plugin.api.GoPluginIdentifier;
import com.thoughtworks.go.plugin.api.annotation.Extension;
import com.thoughtworks.go.plugin.api.logging.Logger;
import com.thoughtworks.go.plugin.api.request.GoPluginApiRequest;
import com.thoughtworks.go.plugin.api.response.GoPluginApiResponse;
import in.ashwanthkumar.gocd.slack.base.AbstractNotificationPlugin;
import in.ashwanthkumar.gocd.slack.ruleset.Rules;
import in.ashwanthkumar.gocd.slack.ruleset.RulesReader;
import in.ashwanthkumar.utils.lang.StringUtils;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import static java.util.Arrays.asList;

@Extension
public class GoNotificationPlugin extends AbstractNotificationPlugin implements GoPlugin {
public class GoNotificationPlugin extends AbstractNotificationPlugin<SlackPluginSettings> implements GoPlugin {
public static final String CRUISE_SERVER_DIR = "CRUISE_SERVER_DIR";
private static final long CONFIG_REFRESH_INTERVAL = 10 * 1000; // 10 seconds


public static final String REQUEST_NOTIFICATIONS_INTERESTED_IN = "notifications-interested-in";
public static final String REQUEST_GET_CONFIGURATION = "go.plugin-settings.get-configuration";
public static final String REQUEST_GET_VIEW = "go.plugin-settings.get-view";
public static final String REQUEST_VALIDATE_CONFIGURATION = "go.plugin-settings.validate-configuration";

public static final int SUCCESS_RESPONSE_CODE = 200;
public static final int INTERNAL_ERROR_RESPONSE_CODE = 500;

public static final String GO_NOTIFY_CONF = "GO_NOTIFY_CONF";
public static final String CONFIG_FILE_NAME = "go_notify.conf";
public static final String HOME_PLUGIN_CONFIG_PATH = System.getProperty("user.home") + File.separator + CONFIG_FILE_NAME;
Expand All @@ -48,6 +31,7 @@ public class GoNotificationPlugin extends AbstractNotificationPlugin implements
private File pluginConfig;

public GoNotificationPlugin() {
super();
pluginConfig = findGoNotifyConfigPath();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
Expand All @@ -70,59 +54,15 @@ public void run() {
}
}
}, 0, CONFIG_REFRESH_INTERVAL);
this.settings = new SlackPluginSettings();
}

// used for tests
GoNotificationPlugin(GoEnvironment environment) {
super();
this.environment = environment;
}

@Override
public void handleStageNotification(GoNotificationMessage notification) throws Exception{
try {
LOGGER.info(notification.fullyQualifiedJobName() + " has " + notification.getStageState() + "/" + notification.getStageResult());
lock.readLock().lock();
rules.getPipelineListener().notify(notification);
} finally {
lock.readLock().unlock();
}
}

@Override
public String template() throws Exception {
return IOUtils.toString(getClass().getResourceAsStream("/views/config.template.html"), "UTF-8");
}


public GoPluginApiResponse handle(GoPluginApiRequest goPluginApiRequest) {
String requestName = goPluginApiRequest.requestName();
switch (requestName) {
case REQUEST_NOTIFICATIONS_INTERESTED_IN:
return handleNotificationsInterestedIn();
case REQUEST_STAGE_STATUS:
return handleStageNotification(goPluginApiRequest);
case REQUEST_GET_VIEW:
return handleRequestGetView();
case REQUEST_VALIDATE_CONFIGURATION:
return handleValidateConfig(goPluginApiRequest.requestBody());
case REQUEST_GET_CONFIGURATION:
return handleRequestGetConfiguration();
}
return null;
}

protected GoPluginApiResponse handleValidateConfig(String requestBody) {
List<Object> response = Arrays.asList();
return renderJSON(SUCCESS_RESPONSE_CODE, response);
}

private GoPluginApiResponse handleRequestGetConfiguration() {
Map<String, Object> response = new TreeMap<>();
response.put("server-url-external", configField("External GoCD Server URL", "", "1", true, false));
response.put("pipelineConfig", configField("Pipeline Notification Rules", "", "2", true, false));
return renderJSON(SUCCESS_RESPONSE_CODE, response);
}

private File findGoNotifyConfigPath() {
// case 1: Look for an environment variable by GO_NOTIFY_CONF and if a file identified by the value exist
String goNotifyConfPath = environment.getenv(GO_NOTIFY_CONF);
Expand All @@ -149,4 +89,20 @@ private File findGoNotifyConfigPath() {

throw new RuntimeException("Unable to find go_notify.conf. Please make sure you've set it up right.");
}

@Override
public void handleStageNotification(GoNotificationMessage notification) throws Exception {
try {
LOGGER.info(notification.fullyQualifiedJobName() + " has " + notification.getStageState() + "/" + notification.getStageResult());
lock.readLock().lock();
rules.getPipelineListener().notify(notification);
} finally {
lock.readLock().unlock();
}
}

@Override
public String template() throws Exception {
return IOUtils.toString(getClass().getResourceAsStream("/views/config.template.html"), "UTF-8");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,33 @@
import com.thoughtworks.go.plugin.api.response.DefaultGoPluginApiResponse;
import com.thoughtworks.go.plugin.api.response.GoPluginApiResponse;
import in.ashwanthkumar.gocd.slack.GoNotificationMessage;
import in.ashwanthkumar.gocd.slack.base.config.Configurations;
import in.ashwanthkumar.gocd.slack.base.config.ConfigurationsParser;
import in.ashwanthkumar.gocd.slack.base.serializer.GsonFactory;
import in.ashwanthkumar.utils.collections.Lists;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.util.*;

import static in.ashwanthkumar.gocd.slack.GoNotificationPlugin.INTERNAL_ERROR_RESPONSE_CODE;
import static in.ashwanthkumar.gocd.slack.GoNotificationPlugin.SUCCESS_RESPONSE_CODE;
import static in.ashwanthkumar.utils.lang.StringUtils.isNotEmpty;

abstract public class AbstractNotificationPlugin implements GoPlugin {
abstract public class AbstractNotificationPlugin<T> implements GoPlugin {
public static final String EXTENSION_TYPE = "notification";

public static final int SUCCESS_RESPONSE_CODE = 200;
public static final int INTERNAL_ERROR_RESPONSE_CODE = 500;

public static final String REQUEST_STAGE_STATUS = "stage-status";
public static final String REQUEST_NOTIFICATIONS_INTERESTED_IN = "notifications-interested-in";
public static final String REQUEST_GET_CONFIGURATION = "go.plugin-settings.get-configuration";
public static final String REQUEST_GET_VIEW = "go.plugin-settings.get-view";
public static final String REQUEST_VALIDATE_CONFIGURATION = "go.plugin-settings.validate-configuration";

protected Logger LOGGER = Logger.getLoggerFor(this.getClass());
protected GoApplicationAccessor goApplicationAccessor;

private Configurations configurations;
protected T settings;

/**
* StageNotification handler of the plugin. For every notification from the server, we'll call this method.
*
Expand All @@ -41,7 +50,9 @@ abstract public class AbstractNotificationPlugin implements GoPlugin {
* @return Entire HTML template as string
* @throws Exception In case of any issues while trying to get the template from a local file / URL.
*/
abstract public String template() throws Exception;
public String template() throws Exception {
return null;
}

public void initializeGoApplicationAccessor(GoApplicationAccessor goApplicationAccessor) {
this.goApplicationAccessor = goApplicationAccessor;
Expand All @@ -51,6 +62,23 @@ public GoPluginIdentifier pluginIdentifier() {
return new GoPluginIdentifier(EXTENSION_TYPE, getGoSupportedVersions());
}

public GoPluginApiResponse handle(GoPluginApiRequest goPluginApiRequest) {
String requestName = goPluginApiRequest.requestName();
switch (requestName) {
case REQUEST_NOTIFICATIONS_INTERESTED_IN:
return handleNotificationsInterestedIn();
case REQUEST_STAGE_STATUS:
return handleStageNotification(goPluginApiRequest);
case REQUEST_GET_VIEW:
return handleRequestGetView();
case REQUEST_VALIDATE_CONFIGURATION:
return handleValidateConfig(goPluginApiRequest.requestBody());
case REQUEST_GET_CONFIGURATION:
return handleRequestGetConfiguration();
}
return null;
}

/**
* List of Go Notification API do we support.
*/
Expand All @@ -65,8 +93,7 @@ protected List<String> subscriptions() {
return Lists.of(REQUEST_STAGE_STATUS);
}

// TODO - Make me private
protected GoPluginApiResponse handleStageNotification(GoPluginApiRequest goPluginApiRequest) {
private GoPluginApiResponse handleStageNotification(GoPluginApiRequest goPluginApiRequest) {
GoNotificationMessage message = parseNotificationMessage(goPluginApiRequest);
int responseCode = SUCCESS_RESPONSE_CODE;

Expand All @@ -90,15 +117,13 @@ protected GoPluginApiResponse handleStageNotification(GoPluginApiRequest goPlugi
return renderJSON(responseCode, response);
}

// TODO - Make me private
protected GoPluginApiResponse handleNotificationsInterestedIn() {
private GoPluginApiResponse handleNotificationsInterestedIn() {
Map<String, Object> response = new HashMap<>();
response.put("notifications", subscriptions());
return renderJSON(SUCCESS_RESPONSE_CODE, response);
}

// TODO - Make me private
protected GoPluginApiResponse handleRequestGetView() {
private GoPluginApiResponse handleRequestGetView() {
Map<String, Object> response = new HashMap<>();

try {
Expand All @@ -112,28 +137,21 @@ protected GoPluginApiResponse handleRequestGetView() {
return renderJSON(SUCCESS_RESPONSE_CODE, response);
}


/**
* Create a configuration field for the plugin.
*
* @param displayName Name of the configuration
* @param defaultValue Default value if none provided
* @param displayOrder Order in which it should be displayed
* @param required If the field is mandatory.
* @param secure If the data in the field should be stored encrypted.
* @return
*/
protected Map<String, Object> configField(String displayName, String defaultValue, String displayOrder, boolean required, boolean secure) {
return new Configuration()
.setDisplayName(displayName)
.setDefaultValue(defaultValue)
.setDisplayOrder(Integer.parseInt(displayOrder))
.setRequired(required)
.setSecure(secure)
.asMap();
private GoPluginApiResponse handleRequestGetConfiguration() {
if(isSettingsConfigured()) {
lazyUpdateConfigurations();
return renderJSON(SUCCESS_RESPONSE_CODE, this.configurations);
}
return renderJSON(SUCCESS_RESPONSE_CODE, new HashMap<String, Object>());
}

private GoPluginApiResponse handleValidateConfig(String requestBody) {
List<Object> response = Arrays.asList();
// TODO - Implement parsing Configurations back to settings
return renderJSON(SUCCESS_RESPONSE_CODE, response);
}

// TODO - Make private
protected GoPluginApiResponse renderJSON(final int responseCode, final Object response) {
final String json = response == null ? null : GsonFactory.getGson().toJson(response);
DefaultGoPluginApiResponse pluginApiResponse = new DefaultGoPluginApiResponse(responseCode);
Expand All @@ -144,4 +162,14 @@ protected GoPluginApiResponse renderJSON(final int responseCode, final Object re
private GoNotificationMessage parseNotificationMessage(GoPluginApiRequest goPluginApiRequest) {
return new GsonBuilder().create().fromJson(goPluginApiRequest.requestBody(), GoNotificationMessage.class);
}

private void lazyUpdateConfigurations() {
if (this.configurations == null) {
this.configurations = ConfigurationsParser.parseConfigurations(settings.getClass());
}
}

private boolean isSettingsConfigured() {
return settings != null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ public void shouldSerializeConfigurationsProperly() {
));
Gson gson = GsonFactory.getGson();
String configAsJson = gson.toJson(configurations);
Map<String, Map<String, Object>> expectedMap = new TreeMap<>();
Map<String, Configuration> expectedMap = new TreeMap<>();
for (Configuration config : configurations) {
expectedMap.put(config.getId(), config.asMap());
expectedMap.put(config.getId(), config);
}
String expectedJson = gson.toJson(expectedMap);

Expand Down

0 comments on commit aa03d1b

Please sign in to comment.