All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mule.runtime.api.component.location.Location Maven / Gradle / Ivy

There is a newer version: 1.1.1
Show newest version
/*
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.runtime.api.component.location;

import static java.lang.String.join;
import static org.apache.commons.lang3.StringUtils.isNumeric;
import static org.mule.runtime.api.component.location.Location.LocationImpl.PARTS_SEPARATOR;
import static org.mule.runtime.api.util.Preconditions.checkArgument;
import static org.mule.runtime.api.util.Preconditions.checkState;

import java.util.LinkedList;
import java.util.List;

/**
 * A location allows to define the position of a certain component in the configuration.
 * 

* Only components contained within global components with name can be referenced using a {@link Location} instance. *

* The string representation of the implementation of this interface must be the serialized form of the location which consist of * the global element name and the parts separated by an slash character. * * @since 1.0 */ public interface Location { String SOURCE = "source"; String CONNECTION = "connection"; String PARAMETERS = "parameters"; String PROCESSORS = "processors"; String ERROR_HANDLER = "errorHandler"; /** * @return the name of the global element that contains the component referenced by {@code this} {@link Location}. */ String getGlobalElementName(); /** * @return the parts within the global element that define the location of the * component referenced by {@code this} {@link Location}. */ List getParts(); /** * @return a new builder instance. */ static Builder builder() { return new LocationBuilder(); } /** * Creates a new {@link Builder} with the provided location represented as string as base. * * @param location a location to use to pre-configured the builder * @return a new builder instance with the provided location as base. */ static Builder builderFromStringRepresentation(String location) { String[] parts = location.split("/"); Builder builder = Location.builder(); builder = builder.globalName(parts[0]); for (int i = 1; i < parts.length; i++) { builder = builder.addPart(parts[i]); } return builder; } /** * A builder to create a {@link Location} object. *

* All {@link Location} instances must be created using this builder. The builder implementation may not be thread safe but it * is immutable so each method call in the builder returns a new instance so it can be reused. * * @since 1.0 */ interface Builder { /** * Sets the name of the global component. This method must only be called once. * * @param globalName the name of the global component * @return a new builder with the provided configuration. */ Builder globalName(String globalName); /** * Adds a new part at the end of the location. * * @param part the name of the part * @return a new builder with the provided configuration. */ Builder addPart(String part); /** * Adds a new {@link Location#CONNECTION} part at the end of the location. *

* Connection elements within a configuration component must be addressed using a {@link Location#CONNECTION} part. * * @return a new builder with the provided configuration. */ Builder addConnectionPart(); /** * Adds a new {@link Location#SOURCE} part at the end of the location. *

* Message sources within other component must be addressed using a {@link Location#SOURCE} part. * * @return a new builder with the provided configuration. */ Builder addSourcePart(); /** * Adds a new {@link Location#PROCESSORS} part at the end of the location. *

* Components that allow nested processors must have {@link Location#PROCESSORS} as part before the nested processors indexes. * * @return a new builder with the provided configuration. */ Builder addProcessorsPart(); /** * Adds a new {@link Location#ERROR_HANDLER} part at the end of the location. *

* Components that allow nested {@code on-error} components must have {@link Location#ERROR_HANDLER} * as part before the {@code on-error} indexes. * * @return a new builder with the provided configuration. */ Builder addErrorHandlerPart(); /** * Adds a new {@link Location#PARAMETERS} part at the end of the location. *

* Components that allow nested parameters must have {@link Location#PARAMETERS} * as part before the {@code parameter} name. * * @return a new builder with the provided configuration. */ Builder addParameterPart(); /** * Adds a new index part. The index part is used to reference a component within a collection. *

* There cannot be two index parts consecutively. * * @param index the index of the component. * @return a new builder with the provided configuration. */ Builder addIndexPart(int index); /** * @return a location built with the provided configuration. */ Location build(); } class LocationImpl implements Location { protected static final String PARTS_SEPARATOR = "/"; private LinkedList parts = new LinkedList<>(); @Override public String getGlobalElementName() { return parts.get(0); } @Override public List getParts() { return parts.subList(1, parts.size()); } @Override public String toString() { return join(PARTS_SEPARATOR, parts); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } LocationImpl location = (LocationImpl) o; return parts.equals(location.parts); } @Override public int hashCode() { return parts.hashCode(); } } class LocationBuilder implements Builder { private LocationImpl location = new LocationImpl(); private boolean globalNameAlreadySet = false; @Override public Builder globalName(String globalName) { globalNameAlreadySet = true; verifyPartDoesNotContainsSlash(globalName); LocationBuilder locationBuilder = builderCopy(); locationBuilder.location.parts.add(0, globalName); return locationBuilder; } @Override public Builder addPart(String part) { verifyPartDoesNotContainsSlash(part); verifyIndexPartAfterProcessor(part); LocationBuilder locationBuilder = builderCopy(); locationBuilder.location.parts.addLast(part); return locationBuilder; } @Override public Builder addConnectionPart() { checkIsNotFirstPart(CONNECTION); LocationBuilder locationBuilder = builderCopy(); locationBuilder.location.parts.add(CONNECTION); return locationBuilder; } @Override public Builder addSourcePart() { checkIsNotFirstPart(SOURCE); LocationBuilder locationBuilder = builderCopy(); locationBuilder.location.parts.add(SOURCE); return locationBuilder; } @Override public Builder addProcessorsPart() { checkIsNotFirstPart(PROCESSORS); LocationBuilder locationBuilder = builderCopy(); locationBuilder.location.parts.add(PROCESSORS); return locationBuilder; } @Override public Builder addErrorHandlerPart() { checkIsNotFirstPart(ERROR_HANDLER); LocationBuilder locationBuilder = builderCopy(); locationBuilder.location.parts.add(ERROR_HANDLER); return locationBuilder; } @Override public Builder addParameterPart() { checkIsNotFirstPart(PARAMETERS); LocationBuilder locationBuilder = builderCopy(); locationBuilder.location.parts.add(PARAMETERS); return locationBuilder; } private void checkIsNotFirstPart(String partName) { checkState(!location.parts.isEmpty(), "[" + partName + "] cannot be the first part"); } @Override public Builder addIndexPart(int index) { checkState(!location.parts.isEmpty(), "An index cannot be the first part"); LocationBuilder locationBuilder = builderCopy(); locationBuilder.location.parts.addLast(String.valueOf(index)); return locationBuilder; } private void verifyIndexPartAfterProcessor(String part) { if (location.parts.getLast().equals(PROCESSORS)) { checkState(isNumeric(part), "Only an index part can follow a processors part"); } } private LocationBuilder builderCopy() { LocationBuilder locationBuilder = new LocationBuilder(); locationBuilder.globalNameAlreadySet = this.globalNameAlreadySet; locationBuilder.location.parts.addAll(this.location.parts); return locationBuilder; } private void verifyPartDoesNotContainsSlash(String globalName) { checkArgument(!globalName.contains(PARTS_SEPARATOR), "Slash cannot be part of the global name or part"); } @Override public Location build() { checkState(globalNameAlreadySet, "global component name must be set"); return location; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy