![JAR search and dependency download from the Maven repository](/logo.png)
net.officefloor.woof.model.woof.WoofChangesImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of officeweb_configuration Show documentation
Show all versions of officeweb_configuration Show documentation
Configuration for WoOF (Web on OfficeFloor)
/*
* OfficeFloor - http://www.officefloor.net
* Copyright (C) 2005-2018 Daniel Sagenschneider
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package net.officefloor.woof.model.woof;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import net.officefloor.activity.procedure.ProcedureFlowType;
import net.officefloor.activity.procedure.ProcedureType;
import net.officefloor.compile.governance.GovernanceType;
import net.officefloor.compile.impl.util.CompileUtil;
import net.officefloor.compile.properties.Property;
import net.officefloor.compile.properties.PropertyList;
import net.officefloor.compile.section.SectionInputType;
import net.officefloor.compile.section.SectionOutputType;
import net.officefloor.compile.section.SectionType;
import net.officefloor.configuration.ConfigurationContext;
import net.officefloor.frame.api.source.SourceContext;
import net.officefloor.frame.impl.construct.source.SourcePropertiesImpl;
import net.officefloor.model.ConnectionModel;
import net.officefloor.model.Model;
import net.officefloor.model.change.Change;
import net.officefloor.model.change.Conflict;
import net.officefloor.model.impl.change.AbstractChange;
import net.officefloor.model.impl.change.AggregateChange;
import net.officefloor.model.impl.change.NoChange;
import net.officefloor.server.http.HttpMethod;
import net.officefloor.web.security.type.HttpSecurityFlowType;
import net.officefloor.web.security.type.HttpSecurityType;
import net.officefloor.web.template.build.WebTemplate;
import net.officefloor.web.template.type.WebTemplateLoader;
import net.officefloor.web.template.type.WebTemplateOutputType;
import net.officefloor.web.template.type.WebTemplateType;
import net.officefloor.woof.template.WoofTemplateExtensionLoader;
import net.officefloor.woof.template.WoofTemplateExtensionLoaderImpl;
/**
* {@link Change} for the {@link WoofModel}.
*
* @author Daniel Sagenschneider
*/
public class WoofChangesImpl implements WoofChanges {
/**
* Sorts the models by name.
*
* @param models Models.
* @param nameExtractor {@link Function} to extract name.
*/
private static void sortModelList(List models, final Function nameExtractor) {
Collections.sort(models, (a, b) -> {
String nameA = nameExtractor.apply(a);
String nameB = nameExtractor.apply(b);
return String.CASE_INSENSITIVE_ORDER.compare(nameA, nameB);
});
}
/**
* Determines if the identifier is unique.
*
* @param identifier Identifier to determine is unique.
* @param changingModel Changing {@link Model}. May be null
for new
* {@link Model} being added.
* @param models Models.
* @param nameExtractor {@link Function} to extract name.
* @return true
if identifier is unique.
*/
private static boolean isUniqueModelIdentifier(String identifier, M changingModel, List models,
final Function nameExtractor) {
return models.stream()
.allMatch((item) -> (item == changingModel) || (!identifier.equals(nameExtractor.apply(item))));
}
/**
* Sorts the {@link WoofTemplateOutputModel} and
* {@link WoofTemplateExtensionModel} instances of the
* {@link WoofTemplateModel}.
*
* @param template {@link WoofTemplateModel}.
*/
private static void sortTemplateConfiguration(WoofTemplateModel template) {
// Sort outputs keeping template render complete output last
sortModelList(template.getOutputs(), (model) -> model.getWoofTemplateOutputName());
// Sort the links
sortModelList(template.getLinks(), (model) -> model.getWoofTemplateLinkName());
// Sort the render HTTP methods
sortModelList(template.getRenderHttpMethods(), (model) -> model.getWoofTemplateRenderHttpMethodName());
}
/**
* Sorts the {@link WoofProcedureOutputModel} instances of the
* {@link WoofProcedureModel}.
*
* @param procedure {@link WoofProcedureModel}.
*/
private static void sortProcedureOutputs(WoofProcedureModel procedure) {
sortModelList(procedure.getOutputs(), (model) -> model.getWoofProcedureOutputName());
}
/**
* Sorts the {@link WoofSectionInputModel} and {@link WoofSectionOutputModel}
* instances of the {@link WoofSectionModel}.
*
* @param section {@link WoofSectionModel}.
*/
private static void sortSectionInputOutputs(WoofSectionModel section) {
sortModelList(section.getInputs(), (model) -> model.getWoofSectionInputName());
sortModelList(section.getOutputs(), (model) -> model.getWoofSectionOutputName());
}
/**
* Sorts the {@link WoofSecurityModel} and {@link WoofSecurityOutputModel}
* instances of the {@link WoofSecurityModel}.
*
* @param security {@link WoofSecurityModel}.
*/
private static void sortSecurityOutputs(WoofSecurityModel security) {
sortModelList(security.getOutputs(), (output) -> output.getWoofSecurityOutputName());
}
/**
* Obtains the unique name.
*
* @param name Base name.
* @param model Model being named. May be null
.
* @param models Listing of the existing models.
* @param nameExtractor {@link Function} to extract the name.
* @return Unique name.
*/
private static String getUniqueName(final String name, M model, List models,
Function nameExtractor) {
// Determine suffix
String uniqueName = name;
int suffix = 1;
boolean isNameExist = false; // first time not include suffix
do {
// Increment suffix should name exist
if (isNameExist) {
suffix++;
uniqueName = name + "-" + suffix;
}
// Check if name already exists
isNameExist = false;
for (M check : models) {
if (check == model) {
continue; // ignore same model
}
String extractedName = nameExtractor.apply(check);
if (uniqueName.equals(extractedName)) {
isNameExist = true;
}
}
} while (isNameExist);
// Return the unique name
return uniqueName;
}
/**
* Removes the {@link ConnectionModel}.
*
* @param connection {@link ConnectionModel} to remove. May be null
* if nothing to remove.
* @param list List to add the removed {@link ConnectionModel} instances.
*/
private static void removeConnection(ConnectionModel connection, List list) {
// Ensure have connection to remove
if (connection == null) {
return;
}
// Remove the connection
connection.remove();
list.add(connection);
}
/**
* Removes the {@link ConnectionModel} instances.
*
* @param connections Listing of {@link ConnectionModel} instances to remove.
* May be null
if nothing to remove.
* @param list List to add the removed {@link ConnectionModel} instances.
*/
private static void removeConnections(List connections, List list) {
// Ensure have connections
if (connections == null) {
return;
}
// Remove the connections
for (C conn : new ArrayList(connections)) {
removeConnection(conn, list);
}
}
/**
* Reconnect the {@link ConnectionModel} instances.
*
* @param connections {@link ConnectionModel} instances to reconnect. May be
* null
if nothing to reconnect.
*/
private static void reconnectConnections(C[] connections) {
// Ensure have connections
if (connections == null) {
return;
}
// Re-connect
for (int i = 0; i < connections.length; i++) {
connections[i].connect();
}
}
/**
* Refactors the {@link WoofTemplateExtensionModel} instances.
*
* @param existingTemplate Existing {@link WoofTemplateModel}. May be
* null
if adding.
* @param newUri New URI. May be null
if removing
* {@link WoofTemplateModel}.
* @param extensions {@link WoofTemplateExtension} instances to
* refactor the {@link WoofTemplateModel} to have.
* May be null
to indicate no changes
* to {@link WoofTemplateExtensionModel} instances
* for the {@link WoofTemplateModel}.
* @param changeTemplate {@link WoofTemplateModel} to be changed.
* @param sourceContext {@link SourceContext}.
* @param configurationContext {@link ConfigurationContext}.
* @param issues {@link WoofChangeIssues}.
* @return {@link Change} to refactor the {@link WoofTemplateExtensionModel}
* instances on the {@link WoofTemplateModel}.
*/
@SuppressWarnings("unchecked")
private static Change refactorExtensions(WoofTemplateModel existingTemplate, String newUri,
WoofTemplateExtension[] extensions, final WoofTemplateModel changeTemplate, SourceContext sourceContext,
ConfigurationContext configurationContext, WoofChangeIssues issues) {
// Create the list of existing extensions
final List existingExtensions = new ArrayList(
(existingTemplate == null ? Collections.EMPTY_LIST : existingTemplate.getExtensions()));
// Create the list of new extensions (loaded later)
final List newExtensions = new LinkedList();
// Create change to refactor extensions
Change change = new AbstractChange(changeTemplate,
"Refactor extensions") {
@Override
public void apply() {
changeTemplate.getExtensions().clear();
changeTemplate.getExtensions().addAll(newExtensions);
}
@Override
public void revert() {
changeTemplate.getExtensions().clear();
changeTemplate.getExtensions().addAll(existingExtensions);
}
};
// Obtain the old application path
String oldApplicationPath = (existingTemplate == null ? null : existingTemplate.getApplicationPath());
// Load the list of new extensions
List availableExtensions = new LinkedList();
availableExtensions.addAll(existingExtensions);
if (extensions != null) {
// Refactor to the provided extensions
for (WoofTemplateExtension newExtension : extensions) {
// Construct the extension model
WoofTemplateExtensionModel extensionModel = new WoofTemplateExtensionModel();
extensionModel.setExtensionClassName(newExtension.getWoofTemplateExtensionSourceClassName());
for (WoofTemplateExtensionProperty property : newExtension.getWoofTemplateExtensionProperties()) {
extensionModel.addProperty(new PropertyModel(property.getName(), property.getValue()));
}
// Refactor the extension
Change> extensionChange = refactorExtension(extensionModel, oldApplicationPath, newUri,
availableExtensions, changeTemplate, sourceContext, configurationContext, issues);
// Include potential change into aggregate change
if (extensionChange != null) {
change = new AggregateChange(changeTemplate, "Refactor extensions", change,
extensionChange);
}
// Add the next extension
newExtensions.add(extensionModel);
}
} else {
// Refactor existing extensions (likely due to URI change)
for (WoofTemplateExtensionModel extensionModel : existingExtensions) {
// Refactor the extension
Change> extensionChange = refactorExtension(extensionModel, oldApplicationPath, newUri,
availableExtensions, changeTemplate, sourceContext, configurationContext, issues);
// Include potential change into aggregate change
if (extensionChange != null) {
change = new AggregateChange(changeTemplate, "Refactor extensions", change,
extensionChange);
}
// Add the next extension
newExtensions.add(extensionModel);
}
}
// Remove available that no longer match extension
for (WoofTemplateExtensionModel extensionModel : new ArrayList(
availableExtensions)) {
// Refactor the extension (to remove)
Change> extensionChange = refactorExtension(extensionModel, oldApplicationPath, null, availableExtensions,
changeTemplate, sourceContext, configurationContext, issues);
// Include potential change into aggregate change
if (extensionChange != null) {
change = new AggregateChange(changeTemplate, "Refactor extensions", change,
extensionChange);
}
}
// Return the change
return change;
}
/**
* Refactors the {@link WoofTemplateExtension} onto the
* {@link WoofTemplateModel}.
*
* @param extension {@link WoofTemplateExtensionModel} to refactor.
* @param oldUri Old URI. May be null
if adding
* {@link WoofTemplateExtensionModel}.
* @param newUri New URI. May be null
if removing
* {@link WoofTemplateExtensionModel}.
* @param existingExtensions Existing {@link WoofTemplateExtensionModel}
* instances. As {@link WoofTemplateExtension}
* instances are refactored they are removed from
* this list.
* @param changeTemplate {@link WoofTemplateModel} being changed.
* @param sourceContext {@link SourceContext}.
* @param configurationContext {@link ConfigurationContext}.
* @param issues {@link WoofChangeIssues}.
* @return {@link Change} to refactor the {@link WoofTemplateExtension}.
*/
private static Change> refactorExtension(WoofTemplateExtensionModel extension, String oldUri, String newUri,
List existingExtensions, WoofTemplateModel changeTemplate,
SourceContext sourceContext, ConfigurationContext configurationContext, WoofChangeIssues issues) {
// Obtain the extension source class
String extensionSourceClassName = extension.getExtensionClassName();
// Obtain the first matching available extension
WoofTemplateExtensionModel matchingExtension = null;
FOUND_EXTENSION: for (Iterator iterator = existingExtensions.iterator(); iterator
.hasNext();) {
WoofTemplateExtensionModel existingExtension = iterator.next();
if (extensionSourceClassName.equals(existingExtension.getExtensionClassName())) {
// Found matching extension
matchingExtension = existingExtension;
iterator.remove(); // remove as matched
break FOUND_EXTENSION;
}
}
// Construct the old properties
SourcePropertiesImpl oldProperties = new SourcePropertiesImpl();
if (matchingExtension == null) {
// No matching extension, so indicate adding
oldUri = null;
} else {
// Load properties for existing extension
for (PropertyModel property : matchingExtension.getProperties()) {
oldProperties.addProperty(property.getName(), property.getValue());
}
}
// Construct the new properties
SourcePropertiesImpl newProperties = new SourcePropertiesImpl();
for (PropertyModel property : extension.getProperties()) {
newProperties.addProperty(property.getName(), property.getValue());
}
// Create the possible change
WoofTemplateExtensionLoader loader = new WoofTemplateExtensionLoaderImpl();
Change> change = loader.refactorTemplateExtension(extensionSourceClassName, oldUri, oldProperties, newUri,
newProperties, configurationContext, sourceContext, issues);
// Return the possible change
return change;
}
/**
* {@link WoofModel}.
*/
private final WoofModel model;
/**
* Initiate.
*
* @param model {@link WoofModel} to change.
*/
public WoofChangesImpl(WoofModel model) {
this.model = model;
}
/**
* Sorts the {@link WoofTemplateModel} instances.
*/
private void sortTemplates() {
sortModelList(this.model.getWoofTemplates(), (model) -> model.getApplicationPath());
}
/**
* Sorts the {@link WoofSecurityModel} instances.
*/
private void sortSecurities() {
sortModelList(this.model.getWoofSecurities(), (model) -> model.getHttpSecurityName());
}
/**
* Sorts the {@link WoofProcedureModel} instances.
*/
private void sortProcedures() {
sortModelList(this.model.getWoofProcedures(), (model) -> model.getWoofProcedureName());
}
/**
* Sorts the {@link WoofSectionModel} instances.
*/
private void sortSections() {
sortModelList(this.model.getWoofSections(), (model) -> model.getWoofSectionName());
}
/**
* Sorts the {@link WoofGovernanceModel} instances.
*/
private void sortGovernances() {
sortModelList(this.model.getWoofGovernances(), (model) -> model.getWoofGovernanceName());
}
/**
* Sorts the {@link WoofGovernanceAreaModel} for the
* {@link WoofGovernanceModel}.
*
* @param governance {@link WoofGovernanceModel} to have its
* {@link WoofGovernanceAreaModel} instances sorted.
*/
private void sortGovernanceAreas(WoofGovernanceModel governance) {
sortModelList(governance.getGovernanceAreas(), (model) -> model.getWidth() + "-" + model.getHeight());
}
/**
* Sorts the {@link WoofResourceModel} instances.
*/
private void sortResources() {
sortModelList(this.model.getWoofResources(), (model) -> model.getResourcePath());
}
/**
* Sorts the {@link WoofExceptionModel} instances.
*/
private void sortExceptions() {
sortModelList(this.model.getWoofExceptions(), (model) -> model.getClassName());
}
/**
* Sorts the {@link WoofHttpContinuationModel} instances.
*/
private void sortHttpContinuations() {
sortModelList(this.model.getWoofHttpContinuations(), (model) -> model.getApplicationPath());
}
/**
* Sorts the {@link WoofHttpInputModel} instances.
*/
private void sortHttpInputs() {
sortModelList(this.model.getWoofHttpInputs(),
(model) -> model.getHttpMethod() + ":" + model.getApplicationPath());
}
/**
* Checks for unique GET application path.
*
* @param applicationPath Application path to check if unique.
* @param modelWithPath {@link Model} with the existing application path
* (not included in check).
* @param changeDescription Change description.
* @return {@link Change} for the {@link Conflict}, or null
no
* {@link Conflict}.
*/
private Change checkUniqueGetApplicationPath(String applicationPath, T modelWithPath,
String changeDescription) {
// Check HTTP Continutations
Change change = this.checkUniqueApplicationPath(applicationPath, modelWithPath, changeDescription,
this.model.getWoofHttpContinuations().stream(), "HTTP Continuation",
(httpContinuation) -> httpContinuation.getApplicationPath());
if (change != null) {
return change;
}
// Check HTTP Inputs (for GET)
change = this.checkUniqueApplicationPath(applicationPath, modelWithPath, changeDescription,
this.model.getWoofHttpInputs().stream().filter((model) -> "GET".equals(model.getHttpMethod())),
"HTTP Input", (httpInput) -> httpInput.getApplicationPath());
if (change != null) {
return change;
}
// Check Templates
change = this.checkUniqueApplicationPath(applicationPath, modelWithPath, changeDescription,
this.model.getWoofTemplates().stream(), "Template", (template) -> template.getApplicationPath());
if (change != null) {
return change;
}
// No conflict in application path
return null;
}
/**
* Checks for unique application path for specified {@link HttpMethod}.
*
* @param httpMethodName Name of the {@link HttpMethod}.
* @param applicationPath Application path to check if unique. {@link Model}
* with the existing application path (not included in
* check).
* @param changeDescription Change description.
* @return {@link Change} for the {@link Conflict}, or null
no
* {@link Conflict}.
*/
private Change checkUniqueMethodApplicationPath(String httpMethodName, String applicationPath,
T modelWithPath, String changeDescription) {
// Handle GET HTTP method
if ("GET".equals(httpMethodName)) {
return this.checkUniqueGetApplicationPath(applicationPath, modelWithPath, changeDescription);
}
// Determine if unique for particular HTTP method
return this.checkUniqueApplicationPath(applicationPath, modelWithPath, changeDescription,
this.model.getWoofHttpInputs().stream().filter((model) -> httpMethodName.equals(model.getHttpMethod())),
"HTTP Input", (httpInput) -> httpInput.getApplicationPath());
}
/**
* Determines if application path is unique within the {@link List}.
*
* @param applicationPath Application path.
* @param modelWithPath {@link Model} with the existing application path
* (not included in check).
* @param changeDescription Change description.
* @param modelList {@link Model} {@link List} to check.
* @param modelItemTypeName Type name of the {@link Model}.
* @param getApplicationPath {@link Function} to obtain the application path
* from the {@link Model}.
* @return {@link Change} for the {@link Conflict}, or null
no
* {@link Conflict}.
*/
private Change checkUniqueApplicationPath(String applicationPath,
T modelWithPath, String changeDescription, Stream modelList, String modelItemTypeName,
Function getApplicationPath) {
// Must have application path
if (CompileUtil.isBlank(applicationPath)) {
return new NoChange(modelWithPath, changeDescription, "Must provide an application path");
}
// Ensure no conflict in application path
boolean isNoConflict = modelList.allMatch((model) -> {
// Ignore if model with the application path
if (modelWithPath == model) {
return true;
}
// Obtain the application path
String modelApplicationPath = getApplicationPath.apply(model);
return (!applicationPath.equals(modelApplicationPath));
});
// Return possible change conflict
return isNoConflict ? null
: new NoChange(modelWithPath, changeDescription,
"Application path '" + applicationPath + "' already configured for " + modelItemTypeName);
}
/**
* Obtains the {@link WoofSectionModel} for the {@link WoofSectionInputModel}.
*
* @param input {@link WoofSectionInputModel}.
* @return {@link WoofSectionModel} containing the {@link WoofSectionInputModel}
* or null
if not within {@link WoofModel}.
*/
public WoofSectionModel getSection(WoofSectionInputModel input) {
// Find the containing section
WoofSectionModel containingSection = null;
for (WoofSectionModel section : this.model.getWoofSections()) {
for (WoofSectionInputModel check : section.getInputs()) {
if (check == input) {
// Found containing section
containingSection = section;
}
}
}
// Return the containing section
return containingSection;
}
/**
* Obtains the {@link WoofGovernanceModel} for the
* {@link WoofGovernanceAreaModel}.
*
* @param area {@link WoofGovernanceAreaModel}.
* @return {@link WoofGovernanceModel} for the {@link WoofGovernanceAreaModel}
* or null
if not within the {@link WoofModel}.
*/
private WoofGovernanceModel getGovernance(WoofGovernanceAreaModel area) {
// Find the containing governance
WoofGovernanceModel containingGovernance = null;
for (WoofGovernanceModel governance : this.model.getWoofGovernances()) {
for (WoofGovernanceAreaModel check : governance.getGovernanceAreas()) {
if (check == area) {
// Found containing governance
containingGovernance = governance;
}
}
}
// Return the containing governance
return containingGovernance;
}
/*
* ======================= WoofChanges =======================
*/
@Override
public Change addHttpContinuation(String applicationPath, boolean isSecure) {
// Create the HTTP continuation
final WoofHttpContinuationModel path = new WoofHttpContinuationModel(isSecure, applicationPath);
// Determine if not unique application path
Change nonUnique = this.checkUniqueGetApplicationPath(applicationPath, path,
"Add HTTP Continuation");
if (nonUnique != null) {
return nonUnique;
}
// Return change to add HTTP continuation
return new AbstractChange(path, "Add HTTP Continuation") {
@Override
public void apply() {
WoofChangesImpl.this.model.addWoofHttpContinuation(path);
WoofChangesImpl.this.sortHttpContinuations();
}
@Override
public void revert() {
WoofChangesImpl.this.model.removeWoofHttpContinuation(path);
}
};
}
@Override
public Change refactorHttpContinuation(WoofHttpContinuationModel continuation,
String applicationPath, boolean isSecure) {
// Determine if not unique application path
Change nonUnique = this.checkUniqueGetApplicationPath(applicationPath, continuation,
"Refactor HTTP Continuation");
if (nonUnique != null) {
return nonUnique;
}
// Capture the existing values
final String existingApplicationPath = continuation.getApplicationPath();
final boolean existingIsSecure = continuation.getIsSecure();
// Refactor
return new AbstractChange(continuation, "Refactor HTTP Continuation") {
@Override
public void apply() {
continuation.setApplicationPath(applicationPath);
continuation.setIsSecure(isSecure);
WoofChangesImpl.this.sortHttpContinuations();
WoofChangesImpl.renameConnections(continuation);
}
@Override
public void revert() {
continuation.setApplicationPath(existingApplicationPath);
continuation.setIsSecure(existingIsSecure);
WoofChangesImpl.this.sortHttpContinuations();
WoofChangesImpl.renameConnections(continuation);
}
};
}
@Override
public Change changeApplicationPath(WoofHttpContinuationModel continuation,
String applicationPath) {
// Determine if not unique application path
Change nonUnique = this.checkUniqueGetApplicationPath(applicationPath, continuation,
"Change Application Path");
if (nonUnique != null) {
return nonUnique;
}
// Capture existing application path
final String existingApplicationPath = continuation.getApplicationPath();
// Change the application path
return new AbstractChange(continuation, "Change Application Path") {
@Override
public void apply() {
continuation.setApplicationPath(applicationPath);
WoofChangesImpl.this.sortHttpContinuations();
WoofChangesImpl.renameConnections(continuation);
}
@Override
public void revert() {
continuation.setApplicationPath(existingApplicationPath);
WoofChangesImpl.this.sortHttpContinuations();
WoofChangesImpl.renameConnections(continuation);
}
};
}
/**
* Renames the {@link ConnectionModel} instances referencing the
* {@link WoofHttpContinuationModel}.
*/
private static void renameConnections(WoofHttpContinuationModel continuation) {
String applicationPath = continuation.getApplicationPath();
for (WoofSectionOutputToWoofHttpContinuationModel conn : continuation.getWoofSectionOutputs()) {
conn.setApplicationPath(applicationPath);
}
for (WoofTemplateOutputToWoofHttpContinuationModel conn : continuation.getWoofTemplateOutputs()) {
conn.setApplicationPath(applicationPath);
}
for (WoofSecurityOutputToWoofHttpContinuationModel conn : continuation.getWoofSecurityOutputs()) {
conn.setApplicationPath(applicationPath);
}
for (WoofExceptionToWoofHttpContinuationModel conn : continuation.getWoofExceptions()) {
conn.setApplicationPath(applicationPath);
}
for (WoofHttpInputToWoofHttpContinuationModel conn : continuation.getWoofHttpInputs()) {
conn.setApplicationPath(applicationPath);
}
for (WoofHttpContinuationToWoofHttpContinuationModel conn : continuation.getWoofHttpContinuations()) {
conn.setApplicationPath(applicationPath);
}
for (WoofProcedureNextToWoofHttpContinuationModel conn : continuation.getWoofProcedureNexts()) {
conn.setApplicationPath(applicationPath);
}
for (WoofProcedureOutputToWoofHttpContinuationModel conn : continuation.getWoofProcedureOutputs()) {
conn.setApplicationPath(applicationPath);
}
}
@Override
public Change removeHttpContinuation(WoofHttpContinuationModel httpContinuation) {
// Ensure HTTP continuation available to remove
boolean isInModel = false;
for (WoofHttpContinuationModel model : this.model.getWoofHttpContinuations()) {
if (model == httpContinuation) {
isInModel = true;
}
}
if (!isInModel) {
// Application path model not in model
return new NoChange(httpContinuation,
"Remove HTTP continuation " + httpContinuation.getApplicationPath(), " is not in WoOF model");
}
// Return change to remove application path
return new AbstractChange(httpContinuation,
"Remove HTTP continuation " + httpContinuation.getApplicationPath()) {
/**
* {@link ConnectionModel} instances.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnections(httpContinuation.getWoofSectionOutputs(), list);
removeConnections(httpContinuation.getWoofTemplateOutputs(), list);
removeConnections(httpContinuation.getWoofSecurityOutputs(), list);
removeConnections(httpContinuation.getWoofExceptions(), list);
removeConnections(httpContinuation.getWoofHttpContinuations(), list);
removeConnections(httpContinuation.getWoofHttpInputs(), list);
removeConnections(httpContinuation.getWoofProcedureNexts(), list);
removeConnections(httpContinuation.getWoofProcedureOutputs(), list);
removeConnection(httpContinuation.getWoofSectionInput(), list);
removeConnection(httpContinuation.getWoofTemplate(), list);
removeConnection(httpContinuation.getWoofSecurity(), list);
removeConnection(httpContinuation.getWoofResource(), list);
removeConnection(httpContinuation.getWoofRedirect(), list);
removeConnection(httpContinuation.getWoofProcedure(), list);
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the HTTP continuation
WoofChangesImpl.this.model.removeWoofHttpContinuation(httpContinuation);
}
@Override
public void revert() {
// Add back the HTTP continuation
WoofChangesImpl.this.model.addWoofHttpContinuation(httpContinuation);
reconnectConnections(this.connections);
WoofChangesImpl.this.sortHttpContinuations();
}
};
}
@Override
public Change addHttpInput(String applicationPath, String httpMethodName, boolean isSecure) {
// Create the HTTP input
final WoofHttpInputModel path = new WoofHttpInputModel(isSecure, httpMethodName, applicationPath);
// Determine if not unique application path
Change nonUnique = this.checkUniqueMethodApplicationPath(httpMethodName, applicationPath,
path, "Add HTTP Input");
if (nonUnique != null) {
return nonUnique;
}
// Return change to add HTTP input
return new AbstractChange(path, "Add HTTP Input") {
@Override
public void apply() {
WoofChangesImpl.this.model.addWoofHttpInput(path);
WoofChangesImpl.this.sortHttpInputs();
}
@Override
public void revert() {
WoofChangesImpl.this.model.removeWoofHttpInput(path);
}
};
}
@Override
public Change refactorHttpInput(final WoofHttpInputModel input, String applicationPath,
String httpMethod, boolean isSecure) {
// Determine if not unique application path
Change nonUnique = this.checkUniqueMethodApplicationPath(httpMethod, applicationPath, input,
"Refactor HTTP Input");
if (nonUnique != null) {
return nonUnique;
}
// Capture existing details
final String existingApplicationPath = input.getApplicationPath();
final String existingHttpMethod = input.getHttpMethod();
final boolean existingIsSecure = input.getIsSecure();
// Return change to refactor
return new AbstractChange(input, "Refactor HTTP Input") {
@Override
public void apply() {
input.setApplicationPath(applicationPath);
input.setHttpMethod(httpMethod);
input.setIsSecure(isSecure);
WoofChangesImpl.this.sortHttpInputs();
}
@Override
public void revert() {
input.setApplicationPath(existingApplicationPath);
input.setHttpMethod(existingHttpMethod);
input.setIsSecure(existingIsSecure);
WoofChangesImpl.this.sortHttpInputs();
}
};
}
@Override
public Change changeApplicationPath(WoofHttpInputModel input, String applicationPath) {
// Determine if not unique application path
Change nonUnique = this.checkUniqueMethodApplicationPath(input.getHttpMethod(),
applicationPath, input, "Change Application Path");
if (nonUnique != null) {
return nonUnique;
}
// Capture existing application path
final String existingApplicationPath = input.getApplicationPath();
// Return change to refactor
return new AbstractChange(input, "Change Application Path") {
@Override
public void apply() {
input.setApplicationPath(applicationPath);
WoofChangesImpl.this.sortHttpInputs();
}
@Override
public void revert() {
input.setApplicationPath(existingApplicationPath);
WoofChangesImpl.this.sortHttpInputs();
}
};
}
@Override
public Change removeHttpInput(WoofHttpInputModel httpInput) {
// Ensure HTTP input available to remove
boolean isInModel = false;
for (WoofHttpInputModel model : this.model.getWoofHttpInputs()) {
if (model == httpInput) {
isInModel = true;
}
}
if (!isInModel) {
// Application path model not in model
return new NoChange(httpInput, "Remove HTTP input " + httpInput.getApplicationPath(),
" is not in WoOF model");
}
// Return change to remove application path
return new AbstractChange(httpInput,
"Remove HTTP input " + httpInput.getHttpMethod() + " " + httpInput.getApplicationPath()) {
/**
* {@link ConnectionModel} instances.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnection(httpInput.getWoofSectionInput(), list);
removeConnection(httpInput.getWoofTemplate(), list);
removeConnection(httpInput.getWoofSecurity(), list);
removeConnection(httpInput.getWoofResource(), list);
removeConnection(httpInput.getWoofHttpContinuation(), list);
removeConnection(httpInput.getWoofProcedure(), list);
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the HTTP input
WoofChangesImpl.this.model.removeWoofHttpInput(httpInput);
}
@Override
public void revert() {
// Add back the HTTP input
WoofChangesImpl.this.model.addWoofHttpInput(httpInput);
reconnectConnections(this.connections);
WoofChangesImpl.this.sortHttpInputs();
}
};
}
@Override
public Change addTemplate(String applicationPath, String templateLocation,
String templateLogicClass, WebTemplateType templateType, String redirectValuesFunction, String contentType,
String charsetName, boolean isTemplateSecure, String linkSeparatorCharacter,
Map linksSecure, String[] renderHttpMethods, WoofTemplateExtension[] extensions,
WoofTemplateChangeContext context) {
// Create the template
final WoofTemplateModel template = new WoofTemplateModel(applicationPath, templateLocation, templateLogicClass,
redirectValuesFunction, contentType, charsetName, linkSeparatorCharacter, isTemplateSecure);
// Determine if not unique application path
Change nonUnique = this.checkUniqueGetApplicationPath(applicationPath, template,
"Add Template");
if (nonUnique != null) {
return nonUnique;
}
// Determine if have links
if (linksSecure != null) {
// Add the links
for (String linkName : linksSecure.keySet()) {
Boolean isLinkSecure = linksSecure.get(linkName);
template.addLink(new WoofTemplateLinkModel(linkName, isLinkSecure.booleanValue()));
}
}
// Determine if have render HTTP methods
if (renderHttpMethods != null) {
// Add the render HTTP methods
for (String renderHttpMethodName : renderHttpMethods) {
template.addRenderHttpMethod(new WoofTemplateRenderHttpMethodModel(renderHttpMethodName));
}
}
// Add the outputs for the template
for (WebTemplateOutputType output : templateType.getWebTemplateOutputTypes()) {
// Ignore escalations
if (output.isEscalationOnly()) {
continue;
}
// Obtain the output details
String outputName = output.getWebTemplateOutputName();
String argumentType = output.getArgumentType();
// Add the Woof Template Output
template.addOutput(new WoofTemplateOutputModel(outputName, argumentType));
}
// Return change to add template
Change change = new AbstractChange(template, "Add Template") {
@Override
public void apply() {
WoofChangesImpl.this.model.addWoofTemplate(template);
WoofChangesImpl.this.sortTemplates();
}
@Override
public void revert() {
WoofChangesImpl.this.model.removeWoofTemplate(template);
}
};
// Obtain the WoOF change issues
WoofChangeIssues issues = context.getWoofChangeIssues();
// Include adding extensions
Change extensionChange = refactorExtensions(null, applicationPath, extensions, template,
context, context.getConfigurationContext(), issues);
if (extensionChange != null) {
change = new AggregateChange(template, change.getChangeDescription(), change,
extensionChange);
}
// Sort template configuration to ensure deterministic configuration
sortTemplateConfiguration(template);
// Return the change
return change;
}
@Override
public Set getInheritableOutputNames(WoofTemplateModel childTemplate) {
Set outputNames = new HashSet<>();
// Load the super templates
WoofTemplateToSuperWoofTemplateModel superLink = childTemplate.getSuperWoofTemplate();
while (superLink != null) {
WoofTemplateModel superTemplate = superLink.getSuperWoofTemplate();
if (superTemplate != null) {
// Load the template outputs
for (WoofTemplateOutputModel output : superTemplate.getOutputs()) {
outputNames.add(output.getWoofTemplateOutputName());
}
}
// Setup for next iteration
superLink = (superTemplate == null) ? null : superTemplate.getSuperWoofTemplate();
}
// Return the output names
return outputNames;
}
@Override
public void loadSuperTemplates(WebTemplate template, WoofTemplateModel woofTemplate,
WebTemplateLoader templateLoader) {
// Function to obtain the super template model
Function getSuperTemplate = (child) -> {
WoofTemplateModel superTemplate = null;
WoofTemplateToSuperWoofTemplateModel conn = child.getSuperWoofTemplate();
if (conn != null) {
superTemplate = conn.getSuperWoofTemplate();
}
return superTemplate;
};
// Load the woof super templates
WoofTemplateModel superTemplateModel = getSuperTemplate.apply(woofTemplate);
while (superTemplateModel != null) {
// Create template for super template
WebTemplate superTemplate = templateLoader.addTemplate(superTemplateModel.getIsTemplateSecure(),
superTemplateModel.getApplicationPath(), superTemplateModel.getTemplateLocation());
// Load as the super template
template.setSuperTemplate(superTemplate);
// Make super template current for next super template
template = superTemplate;
// Obtain the further super template
superTemplateModel = getSuperTemplate.apply(superTemplateModel);
}
}
@Override
public Change linkTemplateToSuperTemplate(WoofTemplateModel childTemplate,
WoofTemplateModel superTemplate) {
// Create the connection
WoofTemplateToSuperWoofTemplateModel conn = new WoofTemplateToSuperWoofTemplateModel(
superTemplate.getApplicationPath(), childTemplate, superTemplate);
// Capture the existing connection
final WoofTemplateToSuperWoofTemplateModel existingConn = childTemplate.getSuperWoofTemplate();
// Return change to link super template
return new AbstractChange(conn, "Link Template to Super Template") {
/**
* Inherited {@link WoofTemplateOutputModel} instances.
*/
private List inheritedOutputs;
@Override
public void apply() {
// Connect template to super template
if (existingConn != null) {
existingConn.remove();
}
conn.connect();
// Obtain the inheritable output names for new super template
final Set inheritableOutputNames = WoofChangesImpl.this
.getInheritableOutputNames(childTemplate);
// Load the list of inheritable outputs
this.inheritedOutputs = new LinkedList<>();
for (WoofTemplateOutputModel output : childTemplate.getOutputs()) {
if (inheritableOutputNames.contains(output.getWoofTemplateOutputName())) {
// Potential inherited link (if not already connected)
boolean isNotLinked = (output.getWoofHttpContinuation() == null)
&& (output.getWoofResource() == null) && (output.getWoofSectionInput() == null)
&& (output.getWoofSecurity() == null) && (output.getWoofTemplate() == null);
if (isNotLinked) {
this.inheritedOutputs.add(output);
}
}
}
// Clear the inherited outputs
for (WoofTemplateOutputModel output : this.inheritedOutputs) {
childTemplate.removeOutput(output);
}
}
@Override
public void revert() {
// Add the template outputs back in
for (WoofTemplateOutputModel output : this.inheritedOutputs) {
childTemplate.addOutput(output);
}
WoofChangesImpl.sortTemplateConfiguration(childTemplate);
// Connect previous possible super template
conn.remove();
if (existingConn != null) {
existingConn.connect();
}
}
};
}
@Override
public Change removeTemplateToSuperTemplate(
WoofTemplateToSuperWoofTemplateModel link) {
return new RemoveLinkChange<>(link, "Remove Template to Super Template");
}
@Override
public Change refactorTemplate(WoofTemplateModel template, String applicationPath,
String templateLocation, String templateLogicClass, WebTemplateType templateType,
String redirectValuesFunction, Set inheritedTemplateOutputNames, String contentType,
String charsetName, boolean isTemplateSecure, String linkSeparatorCharacter,
Map linksSecure, String[] renderHttpMethods, WoofTemplateExtension[] extensions,
Map templateOutputNameMapping, WoofTemplateChangeContext context) {
// Determine if not unique application path
Change nonUnique = this.checkUniqueGetApplicationPath(applicationPath, template,
"Refactor Template");
if (nonUnique != null) {
return nonUnique;
}
// Create change to sort outputs
Change sortChange = new AbstractChange(template, "Sort outputs") {
@Override
public void apply() {
sortTemplateConfiguration(template);
}
@Override
public void revert() {
this.apply(); // sort
}
};
// Provide list of changes to aggregate
List> changes = new LinkedList>();
// Sort outputs at start (so revert has right order)
changes.add(sortChange);
// Obtain the existing details
final String existingApplicationPath = template.getApplicationPath();
final boolean existingIsTemplateSecure = template.getIsTemplateSecure();
final String existingTemplateLocation = template.getTemplateLocation();
final String existingTemplateClassName = template.getTemplateClassName();
final String existingContentType = template.getTemplateContentType();
final String existingCharsetName = template.getTemplateCharset();
final String existingRedirectValuesFunction = template.getRedirectValuesFunction();
final String existingLinkSeparatorCharacter = template.getLinkSeparatorCharacter();
final List existingTemplateLinks = new ArrayList(
template.getLinks());
final List existingTemplateRenderHttpMethods = new ArrayList<>(
template.getRenderHttpMethods());
// Create change to attributes
Change attributeChange = new AbstractChange(template,
"Refactor attributes") {
@Override
public void apply() {
// Refactor details
template.setApplicationPath(applicationPath);
template.setIsTemplateSecure(isTemplateSecure);
template.setTemplateLocation(templateLocation);
template.setTemplateClassName(templateLogicClass);
template.setTemplateContentType(contentType);
template.setTemplateCharset(charsetName);
template.setRedirectValuesFunction(redirectValuesFunction);
template.setLinkSeparatorCharacter(linkSeparatorCharacter);
// Refactor the links
for (WoofTemplateLinkModel link : new ArrayList(template.getLinks())) {
template.removeLink(link);
}
if (linksSecure != null) {
// Add the refactored links
for (String linkName : linksSecure.keySet()) {
Boolean isLinkSecure = linksSecure.get(linkName);
template.addLink(new WoofTemplateLinkModel(linkName, isLinkSecure.booleanValue()));
}
}
// Refactor the render HTTP methods
for (WoofTemplateRenderHttpMethodModel renderHttpMethod : new ArrayList<>(
template.getRenderHttpMethods())) {
template.removeRenderHttpMethod(renderHttpMethod);
}
if (renderHttpMethods != null) {
// Add the render HTTP methods
for (String renderHttpMethod : renderHttpMethods) {
template.addRenderHttpMethod(new WoofTemplateRenderHttpMethodModel(renderHttpMethod));
}
}
// Ensure reflect application path change
WoofChangesImpl.this.sortTemplates();
WoofChangesImpl.renameConnections(template);
}
@Override
public void revert() {
// Revert attributes
template.setApplicationPath(existingApplicationPath);
template.setIsTemplateSecure(existingIsTemplateSecure);
template.setTemplateLocation(existingTemplateLocation);
template.setTemplateClassName(existingTemplateClassName);
template.setTemplateContentType(existingContentType);
template.setTemplateCharset(existingCharsetName);
template.setRedirectValuesFunction(existingRedirectValuesFunction);
template.setLinkSeparatorCharacter(existingLinkSeparatorCharacter);
// Revert the links
for (WoofTemplateLinkModel link : new ArrayList<>(template.getLinks())) {
template.removeLink(link);
}
for (WoofTemplateLinkModel link : existingTemplateLinks) {
template.addLink(link);
}
// Revert the render HTTP methods
for (WoofTemplateRenderHttpMethodModel renderHttpMethod : new ArrayList<>(
template.getRenderHttpMethods())) {
template.removeRenderHttpMethod(renderHttpMethod);
}
for (WoofTemplateRenderHttpMethodModel renderHttpMethod : existingTemplateRenderHttpMethods) {
template.addRenderHttpMethod(renderHttpMethod);
}
// Ensure reflect application path change
WoofChangesImpl.this.sortTemplates();
WoofChangesImpl.renameConnections(template);
}
};
changes.add(attributeChange);
// Obtain the WoOF change issues
WoofChangeIssues issues = context.getWoofChangeIssues();
// Refactor extensions (ensuring have extensions)
extensions = (extensions == null ? new WoofTemplateExtension[0] : extensions);
Change extensionChange = refactorExtensions(template, applicationPath, extensions, template,
context, context.getConfigurationContext(), issues);
if (extensionChange != null) {
changes.add(extensionChange);
}
// Obtain the mapping of existing outputs
Map existingOutputNameMapping = new HashMap();
for (WoofTemplateOutputModel output : template.getOutputs()) {
existingOutputNameMapping.put(output.getWoofTemplateOutputName(), output);
}
// Refactor the outputs (either refactoring, adding or removing)
for (final WebTemplateOutputType outputType : templateType.getWebTemplateOutputTypes()) {
// Ignore escalations
if (outputType.isEscalationOnly()) {
continue;
}
// Obtain the output details
final String outputName = outputType.getWebTemplateOutputName();
final String argumentType = outputType.getArgumentType();
// Ignore if inheriting the output configuration
if ((inheritedTemplateOutputNames != null) && (inheritedTemplateOutputNames.contains(outputName))) {
continue;
}
// Obtain the mapped section output model
String mappedOutputName = templateOutputNameMapping.get(outputName);
final WoofTemplateOutputModel existingOutputModel = existingOutputNameMapping.remove(mappedOutputName);
// Determine action to take based on existing output
Change templateOutputChange;
if (existingOutputModel != null) {
// Create change to refactor existing output
final String existingOutputName = existingOutputModel.getWoofTemplateOutputName();
final String existingArgumentType = existingOutputModel.getArgumentType();
templateOutputChange = new AbstractChange(existingOutputModel,
"Refactor Template Output") {
@Override
public void apply() {
existingOutputModel.setWoofTemplateOutputName(outputName);
existingOutputModel.setArgumentType(argumentType);
}
@Override
public void revert() {
existingOutputModel.setWoofTemplateOutputName(existingOutputName);
existingOutputModel.setArgumentType(existingArgumentType);
}
};
} else {
// Create change to add output (with no URI)
final WoofTemplateOutputModel newOutputModel = new WoofTemplateOutputModel(outputName, argumentType);
templateOutputChange = new AbstractChange(newOutputModel,
"Add Template Output") {
@Override
public void apply() {
template.addOutput(newOutputModel);
}
@Override
public void revert() {
template.removeOutput(newOutputModel);
}
};
}
changes.add(templateOutputChange);
}
for (final WoofTemplateOutputModel unmappedOutputModel : existingOutputNameMapping.values()) {
// Create change to remove the unmapped output model
Change unmappedOutputChange = new AbstractChange(
unmappedOutputModel, "Remove Template Output") {
/**
* {@link ConnectionModel} instances removed.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnection(unmappedOutputModel.getWoofResource(), list);
removeConnection(unmappedOutputModel.getWoofSectionInput(), list);
removeConnection(unmappedOutputModel.getWoofTemplate(), list);
removeConnection(unmappedOutputModel.getWoofSecurity(), list);
removeConnection(unmappedOutputModel.getWoofHttpContinuation(), list);
removeConnection(unmappedOutputModel.getWoofProcedure(), list);
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the template output
template.removeOutput(unmappedOutputModel);
}
@Override
public void revert() {
// Add output back to template
template.addOutput(unmappedOutputModel);
// Add back in connections
reconnectConnections(this.connections);
}
};
changes.add(unmappedOutputChange);
}
// Sort outputs at end (so apply has right order)
changes.add(sortChange);
// Create the aggregate change for refactoring
Change change = new AggregateChange(template, "Refactor Template",
changes.toArray(new Change[changes.size()]));
// Return the change for refactoring
return change;
}
@Override
public Change changeApplicationPath(final WoofTemplateModel template,
final String applicationPath, WoofTemplateChangeContext context) {
// Determine if not unique application path
Change nonUnique = this.checkUniqueGetApplicationPath(applicationPath, template,
"Change Template Application Path");
if (nonUnique != null) {
return nonUnique;
}
// Keep track of original values
final String originalApplicationPath = template.getApplicationPath();
// Create change to template URI
Change change = new AbstractChange(template,
"Change Template Application Path") {
@Override
public void apply() {
template.setApplicationPath(applicationPath);
WoofChangesImpl.this.sortTemplates();
WoofChangesImpl.renameConnections(template);
}
@Override
public void revert() {
template.setApplicationPath(originalApplicationPath);
WoofChangesImpl.this.sortTemplates();
WoofChangesImpl.renameConnections(template);
}
};
// Obtain the WoOF change issues
WoofChangeIssues issues = context.getWoofChangeIssues();
// Refactor extensions for changed URI
Change extensionChange = refactorExtensions(template, applicationPath, null, template,
context, context.getConfigurationContext(), issues);
if (extensionChange != null) {
change = new AggregateChange(template, change.getChangeDescription(), change,
extensionChange);
}
// Return the change
return change;
}
/**
* Renames the {@link ConnectionModel} instances referencing the
* {@link WoofTemplateModel}.
*/
private static void renameConnections(WoofTemplateModel template) {
String applicationPath = template.getApplicationPath();
for (WoofTemplateToSuperWoofTemplateModel conn : template.getChildWoofTemplates()) {
conn.setSuperWoofTemplateApplicationPath(template.getApplicationPath());
}
for (WoofSectionOutputToWoofTemplateModel conn : template.getWoofSectionOutputs()) {
conn.setApplicationPath(applicationPath);
}
for (WoofTemplateOutputToWoofTemplateModel conn : template.getWoofTemplateOutputs()) {
conn.setApplicationPath(applicationPath);
}
for (WoofSecurityOutputToWoofTemplateModel conn : template.getWoofSecurityOutputs()) {
conn.setApplicationPath(applicationPath);
}
for (WoofExceptionToWoofTemplateModel conn : template.getWoofExceptions()) {
conn.setApplicationPath(applicationPath);
}
for (WoofHttpInputToWoofTemplateModel conn : template.getWoofHttpInputs()) {
conn.setApplicationPath(applicationPath);
}
for (WoofHttpContinuationToWoofTemplateModel conn : template.getWoofHttpContinuations()) {
conn.setApplicationPath(applicationPath);
}
for (WoofProcedureNextToWoofTemplateModel conn : template.getWoofProcedureNexts()) {
conn.setApplicationPath(applicationPath);
}
for (WoofProcedureOutputToWoofTemplateModel conn : template.getWoofProcedureOutputs()) {
conn.setApplicationPath(applicationPath);
}
}
@Override
public Change removeTemplate(final WoofTemplateModel template,
WoofTemplateChangeContext context) {
// Obtain the application path
String applicationPath = template.getApplicationPath();
// Ensure template available to remove
boolean isInModel = false;
for (WoofTemplateModel model : this.model.getWoofTemplates()) {
if (model == template) {
isInModel = true;
}
}
if (!isInModel) {
// Template model not in model
return new NoChange(template, "Remove template " + applicationPath,
"Template " + applicationPath + " is not in WoOF model");
}
// Create change to remove template
Change change = new AbstractChange(template,
"Remove template " + applicationPath) {
/**
* {@link ConnectionModel} instances.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnection(template.getSuperWoofTemplate(), list);
removeConnections(template.getChildWoofTemplates(), list);
removeConnections(template.getWoofTemplateOutputs(), list);
removeConnections(template.getWoofSectionOutputs(), list);
removeConnections(template.getWoofSecurityOutputs(), list);
removeConnections(template.getWoofExceptions(), list);
removeConnections(template.getWoofHttpContinuations(), list);
removeConnections(template.getWoofHttpInputs(), list);
removeConnections(template.getWoofProcedureNexts(), list);
removeConnections(template.getWoofProcedureOutputs(), list);
for (WoofTemplateOutputModel output : template.getOutputs()) {
removeConnection(output.getWoofTemplate(), list);
removeConnection(output.getWoofSectionInput(), list);
removeConnection(output.getWoofSecurity(), list);
removeConnection(output.getWoofResource(), list);
removeConnection(output.getWoofHttpContinuation(), list);
removeConnection(output.getWoofProcedure(), list);
}
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the template
WoofChangesImpl.this.model.removeWoofTemplate(template);
}
@Override
public void revert() {
// Add back the template
WoofChangesImpl.this.model.addWoofTemplate(template);
reconnectConnections(this.connections);
WoofChangesImpl.this.sortTemplates();
}
};
// Obtain the WoOF change issues
WoofChangeIssues issues = context.getWoofChangeIssues();
// Refactor extensions for removing template
Change extensionChange = refactorExtensions(template, null, null, template, context,
context.getConfigurationContext(), issues);
if (extensionChange != null) {
change = new AggregateChange(template, change.getChangeDescription(), change,
extensionChange);
}
// Return the change
return change;
}
@Override
public Change addSection(String sectionName, String sectionSourceClassName,
String sectionLocation, PropertyList properties, SectionType section) {
// Obtain the unique section name
sectionName = getUniqueName(sectionName, null, this.model.getWoofSections(),
(model) -> model.getWoofSectionName());
// Create the section
final WoofSectionModel woofSection = new WoofSectionModel(sectionName, sectionSourceClassName, sectionLocation);
// Add the properties (if available)
if (properties != null) {
for (Property property : properties) {
woofSection.addProperty(new PropertyModel(property.getName(), property.getValue()));
}
}
// Add the inputs
for (SectionInputType input : section.getSectionInputTypes()) {
String inputName = input.getSectionInputName();
String parameterType = input.getParameterType();
woofSection.addInput(new WoofSectionInputModel(inputName, parameterType));
}
// Add the outputs
for (SectionOutputType output : section.getSectionOutputTypes()) {
// Ignore escalations
if (output.isEscalationOnly()) {
continue;
}
// Add the output
String outputName = output.getSectionOutputName();
String argumentType = output.getArgumentType();
woofSection.addOutput(new WoofSectionOutputModel(outputName, argumentType));
}
// Sort the inputs/outputs
sortSectionInputOutputs(woofSection);
// Return the change to add section
return new AbstractChange(woofSection, "Add Section") {
@Override
public void apply() {
WoofChangesImpl.this.model.addWoofSection(woofSection);
WoofChangesImpl.this.sortSections();
}
@Override
public void revert() {
WoofChangesImpl.this.model.removeWoofSection(woofSection);
}
};
}
@Override
public Change refactorSection(final WoofSectionModel section, final String sectionName,
final String sectionSourceClassName, final String sectionLocation, final PropertyList properties,
final SectionType sectionType, Map sectionInputNameMapping,
Map sectionOutputNameMapping) {
// Ensure section available to remove
boolean isInModel = false;
for (WoofSectionModel model : this.model.getWoofSections()) {
if (model == section) {
isInModel = true;
}
}
if (!isInModel) {
// Section model not in model
return new NoChange(section, "Refactor section",
"Section " + section.getWoofSectionName() + " is not in WoOF model");
}
// Create change to sort inputs/outputs
Change sortChange = new AbstractChange(section, "Sort inputs/outputs") {
@Override
public void apply() {
sortSectionInputOutputs(section);
}
@Override
public void revert() {
this.apply(); // sort
}
};
// Provide list of changes to aggregate
List> changes = new LinkedList>();
// Sort inputs/outputs at start (so revert has right order)
changes.add(sortChange);
// Obtain the existing details
final String existingSectionName = section.getWoofSectionName();
final String existingSectionSourceClassName = section.getSectionSourceClassName();
final String existingSectionLocation = section.getSectionLocation();
final List existingProperties = new ArrayList(section.getProperties());
// Create change to attributes and properties
Change attributeChange = new AbstractChange(section,
"Refactor attributes") {
@Override
public void apply() {
// Refactor details
section.setWoofSectionName(sectionName);
section.setSectionSourceClassName(sectionSourceClassName);
section.setSectionLocation(sectionLocation);
// Refactor the properties
section.getProperties().clear();
if (properties != null) {
for (Property property : properties) {
section.addProperty(new PropertyModel(property.getName(), property.getValue()));
}
}
}
@Override
public void revert() {
// Revert attributes
section.setWoofSectionName(existingSectionName);
section.setSectionSourceClassName(existingSectionSourceClassName);
section.setSectionLocation(existingSectionLocation);
// Revert the properties
section.getProperties().clear();
for (PropertyModel property : existingProperties) {
section.addProperty(property);
}
}
};
changes.add(attributeChange);
// Obtain the mapping of existing inputs
Map existingInputNameMapping = new HashMap<>();
for (WoofSectionInputModel input : section.getInputs()) {
existingInputNameMapping.put(input.getWoofSectionInputName(), input);
}
// Refactor the inputs (either refactoring, adding or removing)
for (final SectionInputType inputType : sectionType.getSectionInputTypes()) {
// Obtain the mapped section input model
final String inputName = inputType.getSectionInputName();
String mappedInputName = sectionInputNameMapping.get(inputName);
final WoofSectionInputModel existingInputModel = existingInputNameMapping.remove(mappedInputName);
// Obtain further type details
final String parameterType = inputType.getParameterType();
// Determine action to take based on existing input
Change sectionInputChange;
if (existingInputModel != null) {
// Create change to refactor existing input
final String existingInputName = existingInputModel.getWoofSectionInputName();
final String existingParameterType = existingInputModel.getParameterType();
sectionInputChange = new AbstractChange(existingInputModel,
"Refactor Section Input") {
@Override
public void apply() {
existingInputModel.setWoofSectionInputName(inputName);
existingInputModel.setParameterType(parameterType);
// Rename connections links
this.renameConnections(existingInputModel, sectionName, inputName);
}
@Override
public void revert() {
existingInputModel.setWoofSectionInputName(existingInputName);
existingInputModel.setParameterType(existingParameterType);
// Revert connection links
this.renameConnections(existingInputModel, existingSectionName, existingInputName);
}
/**
* Renames the {@link WoofSectionInputModel} connection names.
*
* @param input {@link WoofSectionInputModel}.
* @param sectionName {@link WoofSectionModel} name.
* @param inputName {@link WoofSectionInputModel} name.
*/
private void renameConnections(WoofSectionInputModel input, String sectionName, String inputName) {
// Rename exception connections
for (WoofExceptionToWoofSectionInputModel conn : input.getWoofExceptions()) {
conn.setSectionName(sectionName);
conn.setInputName(inputName);
}
// Rename section output connections
for (WoofSectionOutputToWoofSectionInputModel conn : input.getWoofSectionOutputs()) {
conn.setSectionName(sectionName);
conn.setInputName(inputName);
}
// Rename start connections
for (WoofStartToWoofSectionInputModel conn : input.getWoofStarts()) {
conn.setSectionName(sectionName);
conn.setInputName(inputName);
}
// Rename template connections
for (WoofTemplateOutputToWoofSectionInputModel conn : input.getWoofTemplateOutputs()) {
conn.setSectionName(sectionName);
conn.setInputName(inputName);
}
// Rename security connections
for (WoofSecurityOutputToWoofSectionInputModel conn : input.getWoofSecurityOutputs()) {
conn.setSectionName(sectionName);
conn.setInputName(inputName);
}
// Rename the HTTP continuation connections
for (WoofHttpContinuationToWoofSectionInputModel conn : input.getWoofHttpContinuations()) {
conn.setSectionName(sectionName);
conn.setInputName(inputName);
}
// Rename the HTTP input connections
for (WoofHttpInputToWoofSectionInputModel conn : input.getWoofHttpInputs()) {
conn.setSectionName(sectionName);
conn.setInputName(inputName);
}
// Rename the procedure next connections
for (WoofProcedureNextToWoofSectionInputModel conn : input.getWoofProcedureNexts()) {
conn.setSectionName(sectionName);
conn.setInputName(inputName);
}
// Rename the procedure output connections
for (WoofProcedureOutputToWoofSectionInputModel conn : input.getWoofProcedureOutputs()) {
conn.setSectionName(sectionName);
conn.setInputName(inputName);
}
}
};
} else {
// Create change to add input (with no URI)
final WoofSectionInputModel newInputModel = new WoofSectionInputModel(inputName, parameterType);
sectionInputChange = new AbstractChange(newInputModel, "Add Section Input") {
@Override
public void apply() {
section.addInput(newInputModel);
}
@Override
public void revert() {
section.removeInput(newInputModel);
}
};
}
changes.add(sectionInputChange);
}
for (final WoofSectionInputModel unmappedInputModel : existingInputNameMapping.values()) {
// Create change to remove the unmapped input model
Change unmappedInputChange = new AbstractChange(
unmappedInputModel, "Remove Section Input") {
/**
* {@link ConnectionModel} instances removed.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnections(unmappedInputModel.getWoofExceptions(), list);
removeConnections(unmappedInputModel.getWoofSectionOutputs(), list);
removeConnections(unmappedInputModel.getWoofStarts(), list);
removeConnections(unmappedInputModel.getWoofTemplateOutputs(), list);
removeConnections(unmappedInputModel.getWoofSecurityOutputs(), list);
removeConnections(unmappedInputModel.getWoofHttpContinuations(), list);
removeConnections(unmappedInputModel.getWoofHttpInputs(), list);
removeConnections(unmappedInputModel.getWoofProcedureNexts(), list);
removeConnections(unmappedInputModel.getWoofProcedureOutputs(), list);
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the section input
section.removeInput(unmappedInputModel);
}
@Override
public void revert() {
// Add input back to section
section.addInput(unmappedInputModel);
// Add back in connections
reconnectConnections(this.connections);
}
};
changes.add(unmappedInputChange);
}
// Obtain the mapping of existing outputs
Map existingOutputNameMapping = new HashMap();
for (WoofSectionOutputModel output : section.getOutputs()) {
existingOutputNameMapping.put(output.getWoofSectionOutputName(), output);
}
// Refactor the outputs (either refactoring, adding or removing)
for (final SectionOutputType outputType : sectionType.getSectionOutputTypes()) {
// Ignore escalations
if (outputType.isEscalationOnly()) {
continue;
}
// Obtain the mapped section output model
final String outputName = outputType.getSectionOutputName();
String mappedOutputName = sectionOutputNameMapping.get(outputName);
final WoofSectionOutputModel existingOutputModel = existingOutputNameMapping.remove(mappedOutputName);
// Obtain further type details
final String argumentType = outputType.getArgumentType();
// Determine action to take based on existing output
Change sectionOutputChange;
if (existingOutputModel != null) {
// Create change to refactor existing output
final String existingOutputName = existingOutputModel.getWoofSectionOutputName();
final String existingArgumentType = existingOutputModel.getArgumentType();
sectionOutputChange = new AbstractChange(existingOutputModel,
"Refactor Section Output") {
@Override
public void apply() {
existingOutputModel.setWoofSectionOutputName(outputName);
existingOutputModel.setArgumentType(argumentType);
}
@Override
public void revert() {
existingOutputModel.setWoofSectionOutputName(existingOutputName);
existingOutputModel.setArgumentType(existingArgumentType);
}
};
} else {
// Create change to add output (with no URI)
final WoofSectionOutputModel newOutputModel = new WoofSectionOutputModel(outputName, argumentType);
sectionOutputChange = new AbstractChange(newOutputModel, "Add Section Output") {
@Override
public void apply() {
section.addOutput(newOutputModel);
}
@Override
public void revert() {
section.removeOutput(newOutputModel);
}
};
}
changes.add(sectionOutputChange);
}
for (final WoofSectionOutputModel unmappedOutputModel : existingOutputNameMapping.values()) {
// Create change to remove the unmapped output model
Change unmappedOutputChange = new AbstractChange(
unmappedOutputModel, "Remove Section Output") {
/**
* {@link ConnectionModel} instances removed.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnection(unmappedOutputModel.getWoofResource(), list);
removeConnection(unmappedOutputModel.getWoofSectionInput(), list);
removeConnection(unmappedOutputModel.getWoofTemplate(), list);
removeConnection(unmappedOutputModel.getWoofSecurity(), list);
removeConnection(unmappedOutputModel.getWoofHttpContinuation(), list);
removeConnection(unmappedOutputModel.getWoofProcedure(), list);
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the section output
section.removeOutput(unmappedOutputModel);
}
@Override
public void revert() {
// Add output back to section
section.addOutput(unmappedOutputModel);
// Add back in connections
reconnectConnections(this.connections);
}
};
changes.add(unmappedOutputChange);
}
// Sort inputs/outputs at end (so apply has right order)
changes.add(sortChange);
// Return aggregate change for refactoring
return new AggregateChange(section, "Refactor Section",
changes.toArray(new Change[changes.size()]));
}
@Override
public Change removeSection(final WoofSectionModel section) {
// Ensure section available to remove
boolean isInModel = false;
for (WoofSectionModel model : this.model.getWoofSections()) {
if (model == section) {
isInModel = true;
}
}
if (!isInModel) {
// Section model not in model
return new NoChange(section, "Remove section " + section.getWoofSectionName(),
"Section " + section.getWoofSectionName() + " is not in WoOF model");
}
// Return change to remove section
return new AbstractChange(section, "Remove section " + section.getWoofSectionName()) {
/**
* {@link ConnectionModel} instances.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
for (WoofSectionInputModel input : section.getInputs()) {
removeConnections(input.getWoofTemplateOutputs(), list);
removeConnections(input.getWoofSectionOutputs(), list);
removeConnections(input.getWoofSecurityOutputs(), list);
removeConnections(input.getWoofExceptions(), list);
removeConnections(input.getWoofHttpContinuations(), list);
removeConnections(input.getWoofHttpInputs(), list);
removeConnections(input.getWoofStarts(), list);
removeConnections(input.getWoofProcedureNexts(), list);
removeConnections(input.getWoofProcedureOutputs(), list);
}
for (WoofSectionOutputModel output : section.getOutputs()) {
removeConnection(output.getWoofTemplate(), list);
removeConnection(output.getWoofSectionInput(), list);
removeConnection(output.getWoofSecurity(), list);
removeConnection(output.getWoofResource(), list);
removeConnection(output.getWoofHttpContinuation(), list);
removeConnection(output.getWoofProcedure(), list);
}
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the section
WoofChangesImpl.this.model.removeWoofSection(section);
}
@Override
public void revert() {
// Add back the section
WoofChangesImpl.this.model.addWoofSection(section);
reconnectConnections(this.connections);
WoofChangesImpl.this.sortSections();
}
};
}
@Override
public Change addProcedure(String procedureName, String resource, String sourceName,
String procedure, PropertyList properties, ProcedureType procedureType) {
// Obtain the unique procedure name
procedureName = getUniqueName(procedureName, null, this.model.getWoofProcedures(),
(model) -> model.getWoofProcedureName());
// Create the procedure
final WoofProcedureModel woofProcedure = new WoofProcedureModel(procedureName, resource, sourceName, procedure);
// Add the properties (if available)
if (properties != null) {
for (Property property : properties) {
woofProcedure.addProperty(new PropertyModel(property.getName(), property.getValue()));
}
}
// Add the flows
for (ProcedureFlowType flow : procedureType.getFlowTypes()) {
// Add the flow
String flowName = flow.getFlowName();
Class> argumentType = flow.getArgumentType();
String argumentTypeName = argumentType == null ? null : argumentType.getName();
woofProcedure.addOutput(new WoofProcedureOutputModel(flowName, argumentTypeName));
}
// Add next details
Class> nextArgumentType = procedureType.getNextArgumentType();
String nextArgumentTypeName = nextArgumentType == null ? null : nextArgumentType.getName();
woofProcedure.setNext(new WoofProcedureNextModel(nextArgumentTypeName));
// Sort the outputs
sortProcedureOutputs(woofProcedure);
// Return the change to add procedure
return new AbstractChange(woofProcedure, "Add Procedure") {
@Override
public void apply() {
WoofChangesImpl.this.model.addWoofProcedure(woofProcedure);
WoofChangesImpl.this.sortProcedures();
}
@Override
public void revert() {
WoofChangesImpl.this.model.removeWoofProcedure(woofProcedure);
}
};
}
@Override
public Change refactorProcedure(WoofProcedureModel procedureModel, String procedureName,
String resource, String sourceName, String procedure, PropertyList properties, ProcedureType procedureType,
Map outputNameMapping) {
// Ensure procedure available to remove
boolean isInModel = false;
for (WoofProcedureModel model : this.model.getWoofProcedures()) {
if (model == procedureModel) {
isInModel = true;
}
}
if (!isInModel) {
// Procedure model not in model
return new NoChange(procedureModel, "Refactor procedure",
"Procedure " + procedureModel.getWoofProcedureName() + " is not in WoOF model");
}
// Create change to sort outputs
Change sortChange = new AbstractChange(procedureModel, "Sort outputs") {
@Override
public void apply() {
sortProcedureOutputs(procedureModel);
}
@Override
public void revert() {
this.apply(); // sort
}
};
// Provide list of changes to aggregate
List> changes = new LinkedList>();
// Sort outputs at start (so revert has right order)
changes.add(sortChange);
// Obtain the existing details
final String existingProcedureName = procedureModel.getWoofProcedureName();
final String existingResource = procedureModel.getResource();
final String existingSourceName = procedureModel.getSourceName();
final String existingProcedure = procedureModel.getProcedureName();
final List existingProperties = new ArrayList(procedureModel.getProperties());
// Obtain the next argument type (ensuring always next)
WoofProcedureNextModel nextModel = procedureModel.getNext();
if (nextModel == null) {
nextModel = new WoofProcedureNextModel();
procedureModel.setNext(nextModel);
}
final String existingNextArgumentType = nextModel.getArgumentType();
// Create change to attributes and properties
Change attributeChange = new AbstractChange(procedureModel,
"Refactor attributes") {
@Override
public void apply() {
// Refactor details
procedureModel.setWoofProcedureName(procedureName);
procedureModel.setResource(resource);
procedureModel.setSourceName(sourceName);
procedureModel.setProcedureName(procedure);
// Refactor the properties
procedureModel.getProperties().clear();
if (properties != null) {
for (Property property : properties) {
procedureModel.addProperty(new PropertyModel(property.getName(), property.getValue()));
}
}
// Specify next argument type
Class> nextArgumentType = procedureType.getNextArgumentType();
procedureModel.getNext().setArgumentType(nextArgumentType == null ? null : nextArgumentType.getName());
}
@Override
public void revert() {
// Revert attributes
procedureModel.setWoofProcedureName(existingProcedureName);
procedureModel.setResource(existingResource);
procedureModel.setSourceName(existingSourceName);
procedureModel.setProcedureName(existingProcedure);
// Revert the properties
procedureModel.getProperties().clear();
for (PropertyModel property : existingProperties) {
procedureModel.addProperty(property);
}
// Revert next argument type
procedureModel.getNext().setArgumentType(existingNextArgumentType);
}
};
changes.add(attributeChange);
// Create change to refactor use of procedure
Change procedureUseChange = new AbstractChange(procedureModel,
"Refactor Procedure Use") {
@Override
public void apply() {
this.renameConnections(procedureModel, procedureName);
}
@Override
public void revert() {
this.renameConnections(procedureModel, existingProcedureName);
}
/**
* Renames the {@link WoofProcedureModel} connection names.
*
* @param procedureModel {@link WoofProcedureModel}.
* @param procedureName {@link WoofProcedureModel} name.
*/
private void renameConnections(WoofProcedureModel procedureModel, String procedureName) {
// Rename exception connections
for (WoofExceptionToWoofProcedureModel conn : procedureModel.getWoofExceptions()) {
conn.setProcedureName(procedureName);
}
// Rename section output connections
for (WoofSectionOutputToWoofProcedureModel conn : procedureModel.getWoofSectionOutputs()) {
conn.setProcedureName(procedureName);
}
// Rename start connections
for (WoofStartToWoofProcedureModel conn : procedureModel.getWoofStarts()) {
conn.setProcedureName(procedureName);
}
// Rename template connections
for (WoofTemplateOutputToWoofProcedureModel conn : procedureModel.getWoofTemplateOutputs()) {
conn.setProcedureName(procedureName);
}
// Rename security connections
for (WoofSecurityOutputToWoofProcedureModel conn : procedureModel.getWoofSecurityOutputs()) {
conn.setProcedureName(procedureName);
}
// Rename the HTTP continuation connections
for (WoofHttpContinuationToWoofProcedureModel conn : procedureModel.getWoofHttpContinuations()) {
conn.setProcedureName(procedureName);
}
// Rename the HTTP input connections
for (WoofHttpInputToWoofProcedureModel conn : procedureModel.getWoofHttpInputs()) {
conn.setProcedureName(procedureName);
}
// Rename the procedure next connections
for (WoofProcedureNextToWoofProcedureModel conn : procedureModel.getWoofProcedureNexts()) {
conn.setProcedureName(procedureName);
}
// Rename the procedure output connections
for (WoofProcedureOutputToWoofProcedureModel conn : procedureModel.getWoofProcedureOutputs()) {
conn.setProcedureName(procedureName);
}
}
};
changes.add(procedureUseChange);
// Obtain the mapping of existing outputs
Map existingOutputNameMapping = new HashMap<>();
for (WoofProcedureOutputModel output : procedureModel.getOutputs()) {
existingOutputNameMapping.put(output.getWoofProcedureOutputName(), output);
}
// Refactor the outputs (either refactoring, adding or removing)
for (final ProcedureFlowType flowType : procedureType.getFlowTypes()) {
// Obtain the mapped procedure output model
final String outputName = flowType.getFlowName();
String mappedOutputName = outputNameMapping.get(outputName);
final WoofProcedureOutputModel existingOutputModel = existingOutputNameMapping.remove(mappedOutputName);
// Obtain further type details
Class> argumentType = flowType.getArgumentType();
final String argumentTypeName = argumentType == null ? null : argumentType.getName();
// Determine action to take based on existing output
Change procedureOutputChange;
if (existingOutputModel != null) {
// Create change to refactor existing output
final String existingOutputName = existingOutputModel.getWoofProcedureOutputName();
final String existingArgumentType = existingOutputModel.getArgumentType();
procedureOutputChange = new AbstractChange(existingOutputModel,
"Refactor Procedure Output") {
@Override
public void apply() {
existingOutputModel.setWoofProcedureOutputName(outputName);
existingOutputModel.setArgumentType(argumentTypeName);
}
@Override
public void revert() {
existingOutputModel.setWoofProcedureOutputName(existingOutputName);
existingOutputModel.setArgumentType(existingArgumentType);
}
};
} else {
// Create change to add output
final WoofProcedureOutputModel newOutputModel = new WoofProcedureOutputModel(outputName,
argumentTypeName);
procedureOutputChange = new AbstractChange(newOutputModel,
"Add Procedure Output") {
@Override
public void apply() {
procedureModel.addOutput(newOutputModel);
}
@Override
public void revert() {
procedureModel.removeOutput(newOutputModel);
}
};
}
changes.add(procedureOutputChange);
}
for (final WoofProcedureOutputModel unmappedOutputModel : existingOutputNameMapping.values()) {
// Create change to remove the unmapped output model
Change unmappedOutputChange = new AbstractChange(
unmappedOutputModel, "Remove Procedure Output") {
/**
* {@link ConnectionModel} instances removed.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnection(unmappedOutputModel.getWoofResource(), list);
removeConnection(unmappedOutputModel.getWoofSectionInput(), list);
removeConnection(unmappedOutputModel.getWoofTemplate(), list);
removeConnection(unmappedOutputModel.getWoofSecurity(), list);
removeConnection(unmappedOutputModel.getWoofHttpContinuation(), list);
removeConnection(unmappedOutputModel.getWoofProcedure(), list);
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the procedure output
procedureModel.removeOutput(unmappedOutputModel);
}
@Override
public void revert() {
// Add output back to procedure
procedureModel.addOutput(unmappedOutputModel);
// Add back in connections
reconnectConnections(this.connections);
}
};
changes.add(unmappedOutputChange);
}
// Sort outputs at end (so apply has right order)
changes.add(sortChange);
// Return aggregate change for refactoring
return new AggregateChange(procedureModel, "Refactor Procedure",
changes.toArray(new Change[changes.size()]));
}
@Override
public Change removeProcedure(WoofProcedureModel procedure) {
// Ensure procedure available to remove
boolean isInModel = false;
for (WoofProcedureModel model : this.model.getWoofProcedures()) {
if (model == procedure) {
isInModel = true;
}
}
if (!isInModel) {
// Procedure model not in model
return new NoChange(procedure, "Remove procedure " + procedure.getWoofProcedureName(),
"Procedure " + procedure.getWoofProcedureName() + " is not in WoOF model");
}
// Return change to remove section
return new AbstractChange(procedure,
"Remove procedure " + procedure.getWoofProcedureName()) {
/**
* {@link ConnectionModel} instances.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnections(procedure.getWoofTemplateOutputs(), list);
removeConnections(procedure.getWoofSectionOutputs(), list);
removeConnections(procedure.getWoofSecurityOutputs(), list);
removeConnections(procedure.getWoofExceptions(), list);
removeConnections(procedure.getWoofHttpContinuations(), list);
removeConnections(procedure.getWoofHttpInputs(), list);
removeConnections(procedure.getWoofStarts(), list);
removeConnections(procedure.getWoofProcedureNexts(), list);
removeConnections(procedure.getWoofProcedureOutputs(), list);
WoofProcedureNextModel next = procedure.getNext();
if (next != null) {
removeConnection(next.getWoofTemplate(), list);
removeConnection(next.getWoofSectionInput(), list);
removeConnection(next.getWoofSecurity(), list);
removeConnection(next.getWoofResource(), list);
removeConnection(next.getWoofHttpContinuation(), list);
removeConnection(next.getWoofProcedure(), list);
}
for (WoofProcedureOutputModel output : procedure.getOutputs()) {
removeConnection(output.getWoofTemplate(), list);
removeConnection(output.getWoofSectionInput(), list);
removeConnection(output.getWoofSecurity(), list);
removeConnection(output.getWoofResource(), list);
removeConnection(output.getWoofHttpContinuation(), list);
removeConnection(output.getWoofProcedure(), list);
}
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the procedure
WoofChangesImpl.this.model.removeWoofProcedure(procedure);
}
@Override
public void revert() {
// Add back the procedure
WoofChangesImpl.this.model.addWoofProcedure(procedure);
reconnectConnections(this.connections);
WoofChangesImpl.this.sortProcedures();
}
};
}
@Override
public Change addSecurity(String httpSecurityName, String httpSecuritySourceClassName,
long timeout, PropertyList properties, String[] contentTypes,
HttpSecurityType, ?, ?, ?, ?> httpSecurityType) {
// Obtain the unique name
httpSecurityName = getUniqueName(httpSecurityName, null, this.model.getWoofSecurities(),
(model) -> model.getHttpSecurityName());
// Create the security
final WoofSecurityModel woofSecurity = new WoofSecurityModel(httpSecurityName, httpSecuritySourceClassName,
timeout);
// Add the properties (if available)
if (properties != null) {
for (Property property : properties) {
woofSecurity.addProperty(new PropertyModel(property.getName(), property.getValue()));
}
}
// Add the content types (if available)
if (contentTypes != null) {
for (String contentType : contentTypes) {
woofSecurity.addContentType(new WoofSecurityContentTypeModel(contentType));
}
}
// Add the outputs
for (HttpSecurityFlowType> output : httpSecurityType.getFlowTypes()) {
// Add the output
String outputName = output.getFlowName();
Class> argumentType = output.getArgumentType();
woofSecurity.addOutput(
new WoofSecurityOutputModel(outputName, (argumentType == null ? null : argumentType.getName())));
}
// Sort the inputs/outputs
sortSecurityOutputs(woofSecurity);
// Create and return change to set access
return new AbstractChange(woofSecurity, "Add Security") {
@Override
public void apply() {
WoofChangesImpl.this.model.addWoofSecurity(woofSecurity);
WoofChangesImpl.this.sortSecurities();
}
@Override
public void revert() {
WoofChangesImpl.this.model.removeWoofSecurity(woofSecurity);
}
};
}
@Override
public Change refactorSecurity(final WoofSecurityModel security, String httpSecurityName,
final String httpSecuritySourceClassName, final long timeout, final PropertyList properties,
String[] contentTypes, HttpSecurityType, ?, ?, ?, ?> httpSecurityType,
Map accessOutputNameMapping) {
// Create change to sort outputs
Change sortChange = new AbstractChange(security, "Sort outputs") {
@Override
public void apply() {
sortSecurityOutputs(security);
WoofChangesImpl.this.sortSecurities();
}
@Override
public void revert() {
this.apply(); // sort
}
};
// Provide list of changes to aggregate
List> changes = new LinkedList>();
// Sort outputs at start (so revert has right order)
changes.add(sortChange);
// Obtain the existing details
final String existingHttpSecurityName = security.getHttpSecurityName();
final String existingHttpSecuritySourceClassName = security.getHttpSecuritySourceClassName();
final long existingTimeout = security.getTimeout();
final List existingProperties = new ArrayList<>(security.getProperties());
final List existingContentTypes = new ArrayList<>(security.getContentTypes());
// Obtain the unique name
final String uniqueHttpSecurityName = getUniqueName(httpSecurityName, security, this.model.getWoofSecurities(),
(model) -> model.getHttpSecurityName());
// Create the listing of new content types
List newContentTypes = new ArrayList<>(
contentTypes == null ? 0 : contentTypes.length);
if (contentTypes != null) {
for (String contentType : contentTypes) {
newContentTypes.add(new WoofSecurityContentTypeModel(contentType));
}
}
// Create change to attributes and properties
Change attributeChange = new AbstractChange(security,
"Refactor attributes") {
@Override
public void apply() {
// Refactor details
security.setHttpSecurityName(uniqueHttpSecurityName);
security.setHttpSecuritySourceClassName(httpSecuritySourceClassName);
security.setTimeout(timeout);
// Refactor the content types
for (WoofSecurityContentTypeModel contentType : existingContentTypes) {
security.removeContentType(contentType);
}
for (WoofSecurityContentTypeModel contentType : newContentTypes) {
security.addContentType(contentType);
}
// Refactor the properties
security.getProperties().clear();
if (properties != null) {
for (Property property : properties) {
security.addProperty(new PropertyModel(property.getName(), property.getValue()));
}
}
// Rename connection links
this.renameConnections();
}
@Override
public void revert() {
// Revert attributes
security.setHttpSecurityName(existingHttpSecurityName);
security.setHttpSecuritySourceClassName(existingHttpSecuritySourceClassName);
security.setTimeout(existingTimeout);
// Revert the content types
for (WoofSecurityContentTypeModel contentType : newContentTypes) {
security.removeContentType(contentType);
}
for (WoofSecurityContentTypeModel contentType : existingContentTypes) {
security.addContentType(contentType);
}
// Revert the properties
security.getProperties().clear();
for (PropertyModel property : existingProperties) {
security.addProperty(property);
}
// Revert connection links
this.renameConnections();
}
/**
* Renames the {@link WoofSecurityModel} connection names.
*/
private void renameConnections() {
String securityName = security.getHttpSecurityName();
// Rename connections
for (WoofExceptionToWoofSecurityModel conn : security.getWoofExceptions()) {
conn.setHttpSecurityName(securityName);
}
for (WoofSectionOutputToWoofSecurityModel conn : security.getWoofSectionOutputs()) {
conn.setHttpSecurityName(securityName);
}
for (WoofTemplateOutputToWoofSecurityModel conn : security.getWoofTemplateOutputs()) {
conn.setHttpSecurityName(securityName);
}
for (WoofSecurityOutputToWoofSecurityModel conn : security.getWoofSecurityOutputs()) {
conn.setHttpSecurityName(securityName);
}
for (WoofHttpContinuationToWoofSecurityModel conn : security.getWoofHttpContinuations()) {
conn.setHttpSecurityName(securityName);
}
for (WoofHttpInputToWoofSecurityModel conn : security.getWoofHttpInputs()) {
conn.setHttpSecurityName(securityName);
}
for (WoofProcedureNextToWoofSecurityModel conn : security.getWoofProcedureNexts()) {
conn.setHttpSecurityName(securityName);
}
for (WoofProcedureOutputToWoofSecurityModel conn : security.getWoofProcedureOutputs()) {
conn.setHttpSecurityName(securityName);
}
}
};
changes.add(attributeChange);
// Create the listing of outputs of resulting refactor
List outputs = new LinkedList();
for (HttpSecurityFlowType> flowType : httpSecurityType.getFlowTypes()) {
// Obtain flow details
final String outputName = flowType.getFlowName();
Class> argumentTypeClass = flowType.getArgumentType();
final String argumentType = (argumentTypeClass == null ? null : argumentTypeClass.getName());
// Create the output for the flow
outputs.add(new ModelItemStruct(outputName, argumentType));
}
// Obtain the mapping of existing outputs
Map existingOutputNameMapping = new HashMap<>();
for (WoofSecurityOutputModel output : security.getOutputs()) {
existingOutputNameMapping.put(output.getWoofSecurityOutputName(), output);
}
// Refactor the outputs (either refactoring, adding or removing)
for (ModelItemStruct output : outputs) {
// Obtain the mapped access output model
final String outputName = output.name;
String mappedOutputName = (accessOutputNameMapping == null ? null
: accessOutputNameMapping.get(outputName));
final WoofSecurityOutputModel existingOutputModel = existingOutputNameMapping.remove(mappedOutputName);
// Obtain further type details
final String argumentType = output.type;
// Determine action to take based on existing output
Change securityOutputChange;
if (existingOutputModel != null) {
// Create change to refactor existing output
final String existingOutputName = existingOutputModel.getWoofSecurityOutputName();
final String existingArgumentType = existingOutputModel.getArgumentType();
securityOutputChange = new AbstractChange(existingOutputModel,
"Refactor Security Output") {
@Override
public void apply() {
existingOutputModel.setWoofSecurityOutputName(outputName);
existingOutputModel.setArgumentType(argumentType);
}
@Override
public void revert() {
existingOutputModel.setWoofSecurityOutputName(existingOutputName);
existingOutputModel.setArgumentType(existingArgumentType);
}
};
} else {
// Create change to add output
final WoofSecurityOutputModel newOutputModel = new WoofSecurityOutputModel(outputName, argumentType);
securityOutputChange = new AbstractChange(newOutputModel,
"Add Security Output") {
@Override
public void apply() {
security.addOutput(newOutputModel);
}
@Override
public void revert() {
security.removeOutput(newOutputModel);
}
};
}
changes.add(securityOutputChange);
}
for (final WoofSecurityOutputModel unmappedOutputModel : existingOutputNameMapping.values()) {
// Create change to remove the unmapped output model
Change unmappedOutputChange = new AbstractChange(
unmappedOutputModel, "Remove Security Output") {
/**
* {@link ConnectionModel} instances removed.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnection(unmappedOutputModel.getWoofResource(), list);
removeConnection(unmappedOutputModel.getWoofSectionInput(), list);
removeConnection(unmappedOutputModel.getWoofTemplate(), list);
removeConnection(unmappedOutputModel.getWoofSecurity(), list);
removeConnection(unmappedOutputModel.getWoofHttpContinuation(), list);
removeConnection(unmappedOutputModel.getWoofProcedure(), list);
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the access output
security.removeOutput(unmappedOutputModel);
}
@Override
public void revert() {
// Add output back to access
security.addOutput(unmappedOutputModel);
// Add back in connections
reconnectConnections(this.connections);
}
};
changes.add(unmappedOutputChange);
}
// Sort inputs/outputs at end (so apply has right order)
changes.add(sortChange);
// Return aggregate change for refactoring
return new AggregateChange(security, "Refactor Security",
changes.toArray(new Change[changes.size()]));
}
/**
* Item of a {@link Model}.
*/
private static class ModelItemStruct {
/**
* Name.
*/
public final String name;
/**
* Type.
*/
public final String type;
/**
* Initiate.
*
* @param name Name.
* @param type Type.
*/
public ModelItemStruct(String name, String type) {
this.name = name;
this.type = type;
}
}
@Override
public Change removeSecurity(final WoofSecurityModel security) {
// Return change to remove access
return new AbstractChange(security, "Remove security " + security.getHttpSecurityName()) {
/**
* {@link ConnectionModel} instances.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnections(security.getWoofSectionOutputs(), list);
removeConnections(security.getWoofTemplateOutputs(), list);
removeConnections(security.getWoofSecurityOutputs(), list);
removeConnections(security.getWoofExceptions(), list);
removeConnections(security.getWoofHttpContinuations(), list);
removeConnections(security.getWoofHttpInputs(), list);
removeConnections(security.getWoofProcedureNexts(), list);
removeConnections(security.getWoofProcedureOutputs(), list);
for (WoofSecurityOutputModel output : security.getOutputs()) {
removeConnection(output.getWoofSectionInput(), list);
removeConnection(output.getWoofTemplate(), list);
removeConnection(output.getWoofSecurity(), list);
removeConnection(output.getWoofResource(), list);
removeConnection(output.getWoofHttpContinuation(), list);
removeConnection(output.getWoofProcedure(), list);
}
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the access
WoofChangesImpl.this.model.removeWoofSecurity(security);
}
@Override
public void revert() {
// Add back the access
WoofChangesImpl.this.model.addWoofSecurity(security);
reconnectConnections(this.connections);
sortSecurityOutputs(security);
WoofChangesImpl.this.sortSecurities();
}
};
}
@Override
public Change addGovernance(String governanceName, String governanceSourceClassName,
PropertyList properties, GovernanceType, ?> governanceType) {
// Obtain the unique governance name
governanceName = getUniqueName(governanceName, null, this.model.getWoofGovernances(),
(model) -> model.getWoofGovernanceName());
// Create the governance
final WoofGovernanceModel woofGovernance = new WoofGovernanceModel(governanceName, governanceSourceClassName);
// Add the properties (if available)
if (properties != null) {
for (Property property : properties) {
woofGovernance.addProperty(new PropertyModel(property.getName(), property.getValue()));
}
}
// Return the change to add governance
return new AbstractChange(woofGovernance, "Add Governance") {
@Override
public void apply() {
WoofChangesImpl.this.model.addWoofGovernance(woofGovernance);
WoofChangesImpl.this.sortGovernances();
}
@Override
public void revert() {
WoofChangesImpl.this.model.removeWoofGovernance(woofGovernance);
}
};
}
@Override
public Change refactorGovernance(final WoofGovernanceModel governance, String governanceName,
final String governanceSourceClassName, final PropertyList properties,
GovernanceType, ?> governanceType) {
// Ensure governance available to remove
boolean isInModel = false;
for (WoofGovernanceModel model : this.model.getWoofGovernances()) {
if (model == governance) {
isInModel = true;
}
}
if (!isInModel) {
// Governance model not in model
return new NoChange(governance,
"Refactor governance " + governance.getWoofGovernanceName(),
"Governance " + governance.getWoofGovernanceName() + " is not in WoOF model");
}
// Obtain the existing details
final String existingGovernanceName = governance.getWoofGovernanceName();
final String existingGovernanceSourceClassName = governance.getGovernanceSourceClassName();
final List existingProperties = new ArrayList(governance.getProperties());
// Obtain the unique governance name
final String uniqueGovernanceName = getUniqueName(governanceName, governance, this.model.getWoofGovernances(),
(model) -> model.getWoofGovernanceName());
// Return change to refactor governance
return new AbstractChange(governance, "Refactor Governance") {
@Override
public void apply() {
// Apply attribute changes
governance.setWoofGovernanceName(uniqueGovernanceName);
governance.setGovernanceSourceClassName(governanceSourceClassName);
// Apply property changes
governance.getProperties().clear();
if (properties != null) {
for (Property property : properties) {
governance.addProperty(new PropertyModel(property.getName(), property.getValue()));
}
}
// Update order of governances (after name change)
WoofChangesImpl.this.sortGovernances();
}
@Override
public void revert() {
// Revert attributes
governance.setWoofGovernanceName(existingGovernanceName);
governance.setGovernanceSourceClassName(existingGovernanceSourceClassName);
// Revert properties
governance.getProperties().clear();
for (PropertyModel property : existingProperties) {
governance.addProperty(property);
}
// Update order of governances (after name revert)
WoofChangesImpl.this.sortGovernances();
}
};
}
@Override
public Change removeGovernance(final WoofGovernanceModel governance) {
// Ensure governance available to remove
boolean isInModel = false;
for (WoofGovernanceModel model : this.model.getWoofGovernances()) {
if (model == governance) {
isInModel = true;
}
}
if (!isInModel) {
// Governance model not in model
return new NoChange(governance,
"Remove governance " + governance.getWoofGovernanceName(),
"Governance " + governance.getWoofGovernanceName() + " is not in WoOF model");
}
// Return change to remove governance
return new AbstractChange(governance,
"Remove governance " + governance.getWoofGovernanceName()) {
@Override
public void apply() {
// Remove the governance
WoofChangesImpl.this.model.removeWoofGovernance(governance);
}
@Override
public void revert() {
// Add back the governance
WoofChangesImpl.this.model.addWoofGovernance(governance);
WoofChangesImpl.this.sortGovernances();
}
};
}
@Override
public Change addGovernanceArea(final WoofGovernanceModel governance, int width,
int height) {
// Create the governance area
final WoofGovernanceAreaModel area = new WoofGovernanceAreaModel(width, height);
// Return the change to add governance area
return new AbstractChange(area, "Add governance area") {
@Override
public void apply() {
governance.addGovernanceArea(area);
WoofChangesImpl.this.sortGovernanceAreas(governance);
}
@Override
public void revert() {
governance.removeGovernanceArea(area);
}
};
}
@Override
public Change removeGovernanceArea(final WoofGovernanceAreaModel governanceArea) {
// Ensure governance area in WoOF to remove
final WoofGovernanceModel governance = this.getGovernance(governanceArea);
if (governance == null) {
// Governance area not in model
return new NoChange(governanceArea, "Remove governance area ",
"Governance area is not in WoOF model");
}
// Return change to remove governance area
return new AbstractChange(governanceArea, "Remove governance area") {
@Override
public void apply() {
// Remove the governance area
governance.removeGovernanceArea(governanceArea);
}
@Override
public void revert() {
// Add back the governance area
governance.addGovernanceArea(governanceArea);
WoofChangesImpl.this.sortGovernanceAreas(governance);
}
};
}
@Override
public Change addResource(String resourcePath) {
// Create the resource
final WoofResourceModel resource = new WoofResourceModel(resourcePath);
// Ensure resource not already added
if (!isUniqueModelIdentifier(resourcePath, resource, this.model.getWoofResources(),
(model) -> model.getResourcePath())) {
return new NoChange(resource, "Add Resource",
"Resource already exists for '" + resourcePath + "'");
}
// Return change to add resource
return new AbstractChange(resource, "Add Resource") {
@Override
public void apply() {
WoofChangesImpl.this.model.addWoofResource(resource);
WoofChangesImpl.this.sortResources();
}
@Override
public void revert() {
WoofChangesImpl.this.model.removeWoofResource(resource);
}
};
}
@Override
public Change refactorResource(WoofResourceModel resource, String resourcePath) {
return this.changeResourcePath(resource, resourcePath, "Refactor Resource");
}
@Override
public Change changeResourcePath(final WoofResourceModel resource, final String resourcePath) {
return this.changeResourcePath(resource, resourcePath, "Change Resource Path");
}
/**
* Changes the path for the {@link WoofResourceModel}.
*
* @param resource {@link WoofResourceModel} to have is path changed.
* @param resourcePath New path for the {@link WoofResourceModel}.
* @param changeDescription Description of type of {@link Change}.
* @return {@link Change} to the path for the {@link WoofResourceModel}.
*/
private Change changeResourcePath(final WoofResourceModel resource, final String resourcePath,
String changeDescription) {
// No change if no resource path
if (CompileUtil.isBlank(resourcePath)) {
return new NoChange(resource, changeDescription, "Must provide resource path");
}
// Ensure resource not already added
if (!isUniqueModelIdentifier(resourcePath, resource, this.model.getWoofResources(),
(model) -> model.getResourcePath())) {
return new NoChange(resource, changeDescription,
"Resource already exists for '" + resourcePath + "'");
}
// Track original values
final String originalResourcePath = resource.getResourcePath();
// Return change to resource path
return new AbstractChange(resource, changeDescription) {
@Override
public void apply() {
resource.setResourcePath(resourcePath);
WoofChangesImpl.this.sortResources();
this.renameConnections();
}
@Override
public void revert() {
resource.setResourcePath(originalResourcePath);
WoofChangesImpl.this.sortResources();
this.renameConnections();
}
/**
* Renames the {@link WoofResourceModel} connection names.
*/
private void renameConnections() {
String resourcePath = resource.getResourcePath();
// Rename connections
for (WoofExceptionToWoofResourceModel conn : resource.getWoofExceptions()) {
conn.setResourcePath(resourcePath);
}
for (WoofSectionOutputToWoofResourceModel conn : resource.getWoofSectionOutputs()) {
conn.setResourcePath(resourcePath);
}
for (WoofTemplateOutputToWoofResourceModel conn : resource.getWoofTemplateOutputs()) {
conn.setResourcePath(resourcePath);
}
for (WoofSecurityOutputToWoofResourceModel conn : resource.getWoofSecurityOutputs()) {
conn.setResourcePath(resourcePath);
}
for (WoofHttpContinuationToWoofResourceModel conn : resource.getWoofHttpContinuations()) {
conn.setResourcePath(resourcePath);
}
for (WoofHttpInputToWoofResourceModel conn : resource.getWoofHttpInputs()) {
conn.setResourcePath(resourcePath);
}
for (WoofProcedureNextToWoofResourceModel conn : resource.getWoofProcedureNexts()) {
conn.setResourcePath(resourcePath);
}
for (WoofProcedureOutputToWoofResourceModel conn : resource.getWoofProcedureOutputs()) {
conn.setResourcePath(resourcePath);
}
}
};
};
@Override
public Change removeResource(final WoofResourceModel resource) {
// Ensure resource available to remove
boolean isInModel = false;
for (WoofResourceModel model : this.model.getWoofResources()) {
if (model == resource) {
isInModel = true;
}
}
if (!isInModel) {
// Resource model not in model
return new NoChange(resource, "Remove resource " + resource.getResourcePath(),
"Resource " + resource.getResourcePath() + " is not in WoOF model");
}
// Return change to remove resource
return new AbstractChange(resource, "Remove resource " + resource.getResourcePath()) {
/**
* {@link ConnectionModel} instances.
*/
private ConnectionModel[] connections;
@Override
public void apply() {
// Remove the connections
List list = new LinkedList();
removeConnections(resource.getWoofTemplateOutputs(), list);
removeConnections(resource.getWoofSectionOutputs(), list);
removeConnections(resource.getWoofSecurityOutputs(), list);
removeConnections(resource.getWoofExceptions(), list);
removeConnections(resource.getWoofHttpContinuations(), list);
removeConnections(resource.getWoofHttpInputs(), list);
removeConnections(resource.getWoofProcedureNexts(), list);
removeConnections(resource.getWoofProcedureOutputs(), list);
this.connections = list.toArray(new ConnectionModel[list.size()]);
// Remove the resource
WoofChangesImpl.this.model.removeWoofResource(resource);
}
@Override
public void revert() {
// Add back the resource
WoofChangesImpl.this.model.addWoofResource(resource);
reconnectConnections(this.connections);
WoofChangesImpl.this.sortResources();
}
};
}
@Override
public Change addException(String exceptionClassName) {
// Create the exception
final WoofExceptionModel exception = new WoofExceptionModel(exceptionClassName);
// Ensure exception not already added
if (!isUniqueModelIdentifier(exceptionClassName, null, this.model.getWoofExceptions(),
(model) -> model.getClassName())) {
return new NoChange(exception, "Add Exception",
"Exception already exists for '" + exceptionClassName + "'");
}
// Return change to add exception
return new AbstractChange