Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package io.pkts.packet.sip.impl;
import io.pkts.buffer.Buffer;
import io.pkts.buffer.Buffers;
import io.pkts.packet.sip.SipMessage;
import io.pkts.packet.sip.SipParseException;
import io.pkts.packet.sip.address.SipURI;
import io.pkts.packet.sip.header.AddressParametersHeader;
import io.pkts.packet.sip.header.CSeqHeader;
import io.pkts.packet.sip.header.CallIdHeader;
import io.pkts.packet.sip.header.ContactHeader;
import io.pkts.packet.sip.header.ContentLengthHeader;
import io.pkts.packet.sip.header.FromHeader;
import io.pkts.packet.sip.header.MaxForwardsHeader;
import io.pkts.packet.sip.header.RecordRouteHeader;
import io.pkts.packet.sip.header.RouteHeader;
import io.pkts.packet.sip.header.SipHeader;
import io.pkts.packet.sip.header.ToHeader;
import io.pkts.packet.sip.header.ViaHeader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* @author [email protected]
*/
public abstract class SipMessageBuilder implements SipMessage.Builder {
/**
* These are all the headers that the user has added to this builder.
* These headers may have been added to this list through any of the
* withXXX-methods or they could have been copied from the
* template if one was used.
*/
private final List headers;
/**
* All headers added to this builder is subject
* to filtering.
*/
private Predicate filter;
private Function onRequestURIFunction;
private CSeqHeader cseq;
private CSeqHeader.Builder cseqBuilder;
private Consumer onMaxForwardsBuilder;
private Consumer> onToBuilder;
private Consumer> onFromBuilder;
private Consumer> onContactBuilder;
private List viaHeaders;
private Consumer onTopMostViaBuilder;
private BiConsumer onViaBuilder;
private List recordRouteHeaders;
private Consumer> onTopMostRecordRouteBuilder;
private Consumer> onRecordRouteBuilder;
private List routeHeaders;
private Consumer> onTopMostRouteBuilder;
private Consumer> onRouteBuilder;
private Function onHeaderFunction;
/**
* TODO: should probably allow to pass in an object as well.
*/
private Buffer body;
private SipHeader toHeader;
private SipHeader fromHeader;
private SipHeader cSeqHeader;
private SipHeader callIdHeader;
private SipHeader maxForwardsHeader;
private SipHeader viaHeader;
private SipHeader routeHeader;
private SipHeader recordRouteHeader;
private SipHeader contactHeader;
/**
* By default, this builder will add certain headers if missing
* but if the user wish to turn off this behavior then she can
* do so by flipping this flag.
*/
private boolean useDefaults = true;
protected SipMessageBuilder(final int headerSizeHint) {
headers = new ArrayList<>(headerSizeHint);
}
protected SipMessageBuilder() {
this(15);
}
@Override
public SipMessage.Builder withNoDefaults() {
useDefaults = false;
return this;
}
@Override
public SipMessage.Builder onHeader(final Function f) throws IllegalStateException {
if (this.onHeaderFunction == null) {
this.onHeaderFunction = f;
} else {
this.onHeaderFunction = this.onHeaderFunction.andThen(f);
}
return this;
}
private void processHeader(final SipHeader header) {
if (header.isContactHeader()) {
addHeader(header);
contactHeader = header;
} else if (header.isCSeqHeader()) {
addHeader(header);
cSeqHeader = header;
} else if (header.isMaxForwardsHeader()) {
addHeader(header);
maxForwardsHeader = header;
} else if (header.isFromHeader()) {
addHeader(header);
fromHeader = header;
} else if (header.isToHeader()) {
addHeader(header);
toHeader = header;
} else if (header.isViaHeader()) {
viaHeaders = ensureList(viaHeaders);
viaHeaders.add(header.ensure().toViaHeader());
viaHeader = header;
} else if (header.isCallIdHeader()) {
addHeader(header);
callIdHeader = header;
} else if (header.isRouteHeader()) {
routeHeaders = ensureList(routeHeaders);
routeHeaders.add(header.ensure().toRouteHeader());
routeHeader = header;
} else if (header.isRecordRouteHeader()) {
recordRouteHeaders = ensureList(recordRouteHeaders);
recordRouteHeaders.add(header.ensure().toRecordRouteHeader());
recordRouteHeader = header;
} else {
addHeader(header);
}
}
private short addHeader(final SipHeader header) {
headers.add(header);
return (short)(headers.size() - 1);
}
@Override
public SipMessage.Builder withHeader(final SipHeader header) {
if (header != null) {
processHeader(header);
}
return this;
}
@Override
public SipMessage.Builder withHeaders(final List headers) {
if (headers != null) {
headers.forEach(this::processHeader);
}
return this;
}
@Override
public SipMessage.Builder withPushHeader(final SipHeader header) {
return this;
}
@Override
public SipMessage.Builder onFromHeader(final Consumer> f) {
if (this.onFromBuilder != null) {
this.onFromBuilder = this.onFromBuilder.andThen(f);
} else {
this.onFromBuilder = f;
}
return this;
}
@Override
public SipMessage.Builder withFromHeader(final FromHeader from) {
if (from != null) {
addHeader(from);
fromHeader = from;
}
return this;
}
@Override
public SipMessage.Builder withFromHeader(final String from) {
return withFromHeader(FromHeader.frame(Buffers.wrap(from)));
}
@Override
public SipMessage.Builder onToHeader(final Consumer> f) {
if (this.onToBuilder != null) {
this.onToBuilder = this.onToBuilder.andThen(f);
} else {
this.onToBuilder = f;
}
return this;
}
@Override
public SipMessage.Builder withToHeader(final ToHeader to) {
if (to != null) {
addHeader(to);
toHeader = to;
}
return this;
}
@Override
public SipMessage.Builder withToHeader(final String to) {
return withToHeader(ToHeader.frame(Buffers.wrap(to)));
}
@Override
public SipMessage.Builder onContactHeader(final Consumer> f) {
if (this.onContactBuilder != null) {
this.onContactBuilder = this.onContactBuilder.andThen(f);
} else {
this.onContactBuilder = f;
}
return this;
}
@Override
public SipMessage.Builder withContactHeader(final ContactHeader contact) {
if (contact != null) {
addHeader(contact);
contactHeader = contact;
}
return this;
}
@Override
public SipMessage.Builder onCSeqHeader(final Consumer f) {
return this;
}
@Override
public SipMessage.Builder withCSeqHeader(final CSeqHeader cseq) {
if (cseq != null) {
addHeader(cseq);
cSeqHeader = cseq;
}
return this;
}
@Override
public SipMessage.Builder withCallIdHeader(final CallIdHeader callID) {
if (callID != null) {
addHeader(callID);
callIdHeader = callID;
}
return this;
}
@Override
public SipMessage.Builder onMaxForwardsHeader(final Consumer f) {
if (this.onMaxForwardsBuilder != null) {
this.onMaxForwardsBuilder.andThen(f);
} else {
this.onMaxForwardsBuilder = f;
}
return this;
}
@Override
public SipMessage.Builder withMaxForwardsHeader(final MaxForwardsHeader maxForwards) {
addHeader(maxForwards);
maxForwardsHeader = maxForwards;
return this;
}
@Override
public SipMessage.Builder onTopMostViaHeader(final Consumer f) {
this.onTopMostViaBuilder = chainConsumers(this.onTopMostViaBuilder, f);
return this;
}
@Override
public SipMessage.Builder onViaHeader(final BiConsumer f) {
this.onViaBuilder = chainConsumers(this.onViaBuilder, f);
return this;
}
@Override
public SipMessage.Builder onTopMostRouteHeader(final Consumer> f) {
this.onTopMostRouteBuilder = chainConsumers(this.onTopMostRouteBuilder, f);
return this;
}
@Override
public SipMessage.Builder onRouteHeader(final Consumer> f) {
this.onRouteBuilder = chainConsumers(this.onRouteBuilder, f);
return this;
}
@Override
public SipMessage.Builder withRouteHeader(final RouteHeader route) {
if (route != null) {
this.routeHeaders = ensureList(this.routeHeaders);
this.routeHeaders.clear();
this.routeHeaders.add(route);
}
return this;
}
@Override
public SipMessage.Builder withRouteHeaders(final RouteHeader... routes) {
if (routes != null && routes.length > 0) {
this.routeHeaders = ensureList(this.routeHeaders);
this.routeHeaders.clear();
routeHeader = routes[0];
this.routeHeaders.addAll(Arrays.asList(routes));
}
return this;
}
@Override
public SipMessage.Builder withRouteHeaders(final List routes) {
if (routes != null && !routes.isEmpty()) {
this.routeHeaders = ensureList(this.routeHeaders);
this.routeHeaders.clear();
routeHeader = routes.get(0);
this.routeHeaders.addAll(routes);
}
return this;
}
@Override
public SipMessage.Builder withTopMostRouteHeader(final RouteHeader route) {
if (route != null) {
this.routeHeaders = ensureList(this.routeHeaders);
this.routeHeaders.add(0, route);
routeHeader = route;
}
return this;
}
@Override
public SipMessage.Builder withPoppedRoute() {
if (this.routeHeaders != null) {
this.routeHeaders.remove(0);
}
return this;
}
@Override
public SipMessage.Builder withNoRoutes() {
if (this.routeHeaders != null) {
this.routeHeaders.clear();
}
return this;
}
@Override
public SipMessage.Builder onTopMostRecordRouteHeader(final Consumer> f) {
this.onTopMostRecordRouteBuilder = chainConsumers(this.onTopMostRecordRouteBuilder, f);
return this;
}
@Override
public SipMessage.Builder onRecordRouteHeader(final Consumer> f) {
this.onRecordRouteBuilder = chainConsumers(this.onRecordRouteBuilder, f);
return this;
}
@Override
public SipMessage.Builder withRecordRouteHeader(final RecordRouteHeader recordRoute) {
if (recordRoute != null) {
this.recordRouteHeaders = ensureList(this.recordRouteHeaders);
this.recordRouteHeaders.clear();
this.recordRouteHeaders.add(recordRoute);
recordRouteHeader = recordRoute;
}
return this;
}
@Override
public SipMessage.Builder withRecordRouteHeaders(final RecordRouteHeader... recordRoutes) {
if (recordRoutes != null && recordRoutes.length > 0) {
this.recordRouteHeaders = ensureList(this.recordRouteHeaders);
this.recordRouteHeaders.clear();
recordRouteHeader = recordRoutes[0];
this.recordRouteHeaders.addAll(Arrays.asList(recordRoutes));
}
return this;
}
@Override
public SipMessage.Builder withRecordRouteHeaders(final List recordRoutes) {
if (recordRoutes != null && !recordRoutes.isEmpty()) {
this.recordRouteHeaders = ensureList(this.recordRouteHeaders);
this.recordRouteHeaders.clear();
recordRouteHeader = recordRoutes.get(0);
this.recordRouteHeaders.addAll(recordRoutes);
}
return this;
}
@Override
public SipMessage.Builder withTopMostRecordRouteHeader(final RecordRouteHeader recordRoute) {
if (recordRoute != null) {
this.recordRouteHeaders = ensureList(this.recordRouteHeaders);
this.recordRouteHeaders.add(0, recordRoute);
recordRouteHeader = recordRoute;
}
return this;
}
@Override
public SipMessage.Builder withViaHeader(final ViaHeader via) {
if (via != null) {
this.viaHeaders = ensureList(this.viaHeaders);
this.viaHeaders.clear();
this.viaHeaders.add(via);
viaHeader = via;
}
return this;
}
@Override
public SipMessage.Builder withViaHeaders(final ViaHeader... vias) {
if (vias != null && vias.length > 0) {
this.viaHeaders = ensureList(this.viaHeaders);
this.viaHeaders.clear();
viaHeader = vias[0];
this.viaHeaders.addAll(Arrays.asList(vias));
}
return this;
}
@Override
public SipMessage.Builder withViaHeaders(final List vias) {
if (vias != null && !vias.isEmpty()) {
this.viaHeaders = ensureList(this.viaHeaders);
this.viaHeaders.clear();
viaHeader = vias.get(0);
this.viaHeaders.addAll(vias);
}
return this;
}
@Override
public SipMessage.Builder withTopMostViaHeader(final ViaHeader via) {
if (via != null) {
this.viaHeaders = ensureList(this.viaHeaders);
this.viaHeaders.add(0, via);
viaHeader = via;
}
return this;
}
@Override
public SipMessage.Builder withTopMostViaHeader() {
this.viaHeaders = ensureList(this.viaHeaders);
this.viaHeaders.add(0, null);
return this;
}
@Override
public SipMessage.Builder withPoppedVia() {
if (this.viaHeaders != null) {
this.viaHeaders.remove(0);
}
return this;
}
protected final Function getRequestURIFunction() {
return this.onRequestURIFunction;
}
private List ensureList(final List list) {
if (list != null) {
return list;
}
// TODO: the initial size of this array could have an impact on performance.
// TODO: Need to do some performance testing...
return new ArrayList(4);
}
@Override
public SipMessage.Builder onRequestURI(final Function f) {
if (this.onRequestURIFunction == null) {
this.onRequestURIFunction = f;
} else {
this.onRequestURIFunction = this.onRequestURIFunction.andThen(f);
}
return this;
}
@Override
public SipMessage.Builder withBody(final Buffer body) {
if (body != null) {
this.body = body.slice();
}
return this;
}
/**
* Special size of method that checks the size of the headers
* we keep track of as a list. The reason we count size() - 1 is
* because the list already occupy one
* @param list
* @return
*/
private final int sizeOf(final List> list) {
return list == null ? 0 : list.size() - 1;
}
/**
* See {@link SipMessage.Builder#withNoDefaults()}, which describes what defaults will
* be pushed. They are copied here for reference:
*
*
*
{@link ToHeader} - the request-uri will be used to construct the to-header
*
{@link CSeqHeader} - a new CSeq header will be added where the
* method is the same as this message and the sequence number is set to 1
*
{@link CallIdHeader} - a new random call-id will be added
*
{@link MaxForwardsHeader} - if we are building a request, then a max forwards of 70 will be added
*
{@link ContentLengthHeader} - Will be added if there is a body
* on the message and the length set to the correct length.
*
*
*/
private void enforceDefaults() {
if (toHeader == null) {
withToHeader(generateDefaultToHeader());
}
if (isBuildingRequest() && maxForwardsHeader == null) {
withMaxForwardsHeader(MaxForwardsHeader.create());
}
if (callIdHeader == null) {
withCallIdHeader(CallIdHeader.create());
}
if (cSeqHeader == null) {
withCSeqHeader(generateDefaultCSeqHeader());
}
}
/**
* Indicates whether or not we are building a request. Must be overridden by
* the request builder. Used for e.g. {@link SipHeaderBuilderWrapper#enforceDefaults()}
*
* @return
*/
protected boolean isBuildingRequest() {
return false;
}
/**
* Indicates whether or not we are building a response. Must be overridden by
* the response builder. Used for e.g. {@link SipHeaderBuilderWrapper#enforceDefaults()}
*
* @return
*/
protected boolean isBuildingResponse() {
return false;
}
protected abstract ToHeader generateDefaultToHeader();
protected abstract CSeqHeader generateDefaultCSeqHeader();
@Override
public T build() {
int msgSize = 2;
final int headerCount = this.headers.size() + sizeOf(viaHeaders) + sizeOf(recordRouteHeaders) + sizeOf(routeHeaders);
final Map> finalHeaders = new HashMap<>(headerCount);
SipHeader contentLengthHeader = null;
if (useDefaults) {
enforceDefaults();
}
// TODO: redo this, it's ugly. Bloody side effect programming & ugly ugly copy-paste crap
toHeader = null;
fromHeader = null;
cSeqHeader = null;
callIdHeader = null;
maxForwardsHeader = null;
viaHeader = null;
routeHeader = null;
recordRouteHeader = null;
contactHeader = null;
for (int i = 0; i < this.headers.size(); ++i) {
final SipHeader header = this.headers.get(i);
if (header != null) {
final SipHeader finalHeader = processFinalHeader((short) finalHeaders.size(), header);
if (finalHeader != null) {
if (finalHeader.isContentLengthHeader()) {
// not that it actually matters but pretty much
// every implementation put the content-length header
// last so we'll do that too...
contentLengthHeader = finalHeader;
} else {
msgSize += finalHeader.getBufferSize() + 2;
finalHeaders.computeIfAbsent(finalHeader.getName().toString(), k -> new ArrayList<>()).add(finalHeader);
}
}
}
}
if (this.viaHeaders != null) {
for (int j = 0; j < this.viaHeaders.size(); ++j) {
final ViaHeader finalVia = processVia(j, this.viaHeaders.get(j));
msgSize += finalVia.getBufferSize() + 2;
if (viaHeader == null) {
viaHeader = finalVia;
}
finalHeaders.computeIfAbsent(finalVia.getName().toString(), k -> new ArrayList<>()).add(finalVia);
}
}
if (this.recordRouteHeaders != null) {
for (int j = 0; j < this.recordRouteHeaders.size(); ++j) {
final Consumer> f =
j == 0 ? this.onTopMostRecordRouteBuilder : this.onRecordRouteBuilder;
final RecordRouteHeader finalRR = invokeAddressBuilderFunction(f, this.recordRouteHeaders.get(j).ensure().toRecordRouteHeader());
msgSize += finalRR.getBufferSize() + 2;
if (recordRouteHeader == null) {
recordRouteHeader = finalRR;
}
finalHeaders.computeIfAbsent(finalRR.getName().toString(), k -> new ArrayList<>()).add(finalRR);
}
}
if (this.routeHeaders != null) {
for (int j = 0; j < this.routeHeaders.size(); ++j) {
final Consumer> f =
j == 0 ? this.onTopMostRouteBuilder : this.onRouteBuilder;
final RouteHeader finalRoute = invokeAddressBuilderFunction(f, this.routeHeaders.get(j).ensure().toRouteHeader());
msgSize += finalRoute.getBufferSize() + 2;
if (routeHeader == null) {
routeHeader = finalRoute;
}
finalHeaders.computeIfAbsent(finalRoute.getName().toString(), k -> new ArrayList<>()).add(finalRoute);
}
}
// TODO: Body - should probably have a onBody as well and we may want
// to allow a "raw" body as well as an object.
final Buffer body = this.body;
// if we are to use defaults then we will adjust the value
// of the Content-Length header. If not, then the CL will be
// whatever the user decided it should be.
if (isBuildingRequest() && useDefaults) {
contentLengthHeader = ContentLengthHeader.create(body == null ? 0 : body.capacity());
}
if (contentLengthHeader != null) {
msgSize += contentLengthHeader.getBufferSize() + 2;
finalHeaders.computeIfAbsent(contentLengthHeader.getName().toString(), k -> new ArrayList<>()).add(contentLengthHeader);
}
// TODO: not correct but will do for now...
final SipInitialLine initialLine = buildInitialLine();
final Buffer initialLineBuffer = initialLine.getBuffer();
msgSize += initialLineBuffer.getReadableBytes() + 2;
if (body != null) {
msgSize += body.getReadableBytes();
}
// TODO: instead of copying over the bytes like this create
// a composite buffer...
final Buffer msg = Buffers.createBuffer(msgSize);
initialLineBuffer.getBytes(msg);
msg.write(SipParser.CR);
msg.write(SipParser.LF);
for (final List headerValues : finalHeaders.values()) {
for (final SipHeader header : headerValues) {
header.getBytes(msg);
msg.write(SipParser.CR);
msg.write(SipParser.LF);
}
}
msg.write(SipParser.CR);
msg.write(SipParser.LF);
if (body != null) {
body.getBytes(msg);
}
return internalBuild(msg,
initialLine,
finalHeaders,
toHeader,
fromHeader,
cSeqHeader,
callIdHeader,
maxForwardsHeader,
viaHeader,
routeHeader,
recordRouteHeader,
contactHeader,
body);
}
private ViaHeader processVia(final int index, final SipHeader header) throws SipParseException {
if (index > 0 && this.onViaBuilder == null) {
if (header == null) {
throw new SipParseException("You cannot register an empty Via-header and "
+ "then not also register a function for that via. Please refer to javadoc");
}
return header.ensure().toViaHeader();
}
if (index == 0 && this.onTopMostViaBuilder == null) {
if (header == null) {
throw new SipParseException("You cannot register an empty top-most Via-header and "
+ "then not also register a function for that top-most via. Please refer to the javadoc");
}
return header.ensure().toViaHeader();
}
final ViaHeader.Builder builder = header == null ? ViaHeader.builder() : header.ensure().toViaHeader().copy();
if (index == 0) {
this.onTopMostViaBuilder.accept(builder);
} else {
this.onViaBuilder.accept(index, builder);
}
return builder.build();
}
protected abstract SipInitialLine buildInitialLine() throws SipParseException;
protected abstract T internalBuild(final Buffer message,
final SipInitialLine initialLine,
final Map> headers,
final SipHeader toHeader,
final SipHeader fromHeader,
final SipHeader cSeqHeader,
final SipHeader callIdHeader,
final SipHeader maxForwardsHeader,
final SipHeader viaHeader,
final SipHeader routeHeader,
final SipHeader recordRouteHeader,
final SipHeader contactHeader,
final Buffer body);
private SipHeader processFinalHeader(final short index, final SipHeader header) {
final SipHeader finalHeader;
if (header.isContactHeader()) {
finalHeader = invokeContactHeaderFunction(header.ensure().toContactHeader());
contactHeader = finalHeader;
} else if (header.isCSeqHeader()) {
finalHeader = header.ensure().toCSeqHeader();
cSeqHeader = finalHeader;
} else if (header.isMaxForwardsHeader()) {
finalHeader = invokeMaxForwardsFunction(header.ensure().toMaxForwardsHeader());
maxForwardsHeader = finalHeader;
} else if (header.isFromHeader()) {
finalHeader = invokeFromHeaderFunction(header.ensure().toFromHeader());
fromHeader = finalHeader;
} else if (header.isToHeader()) {
finalHeader = invokeToHeaderFunction(header.ensure().toToHeader());
toHeader = finalHeader;
} else if (header.isCallIdHeader()) {
finalHeader = header.ensure().toCallIdHeader();
callIdHeader = finalHeader;
} else {
finalHeader = processGenericHeader(header);
}
return finalHeader;
}
private T invokeSipHeaderBuilderFunction(final Consumer> f,
final T header) {
if (header != null && f != null) {
final SipHeader.Builder b = header.copy();
f.accept(b);
return b.build();
}
return header;
}
private T invokeAddressBuilderFunction(final Consumer> f,
final T header) {
if (header != null && f != null) {
final AddressParametersHeader.Builder b = header.copy();
f.accept(b);
return b.build();
}
return header;
}
private SipHeader processGenericHeader(final SipHeader header) {
if (this.onHeaderFunction != null) {
return this.onHeaderFunction.apply(header);
}
return header;
}
private ToHeader invokeToHeaderFunction(final ToHeader to) {
if (to != null && onToBuilder != null) {
final AddressParametersHeader.Builder b = to.copy();
onToBuilder.accept(b);
return b.build();
}
return to;
}
private ContactHeader invokeContactHeaderFunction(final ContactHeader contact) {
if (contact != null && onContactBuilder != null) {
final AddressParametersHeader.Builder b = contact.copy();
onContactBuilder.accept(b);
return b.build();
}
return contact;
}
private FromHeader invokeFromHeaderFunction(final FromHeader from) {
if (from != null && onFromBuilder != null) {
final AddressParametersHeader.Builder b = from.copy();
onFromBuilder.accept(b);
return b.build();
}
return from;
}
private MaxForwardsHeader invokeMaxForwardsFunction(final MaxForwardsHeader max) {
if (max != null && onMaxForwardsBuilder != null) {
final MaxForwardsHeader.Builder b = max.copy();
onMaxForwardsBuilder.accept(b);
return b.build();
}
return max;
}
@Override
public SipMessage.Builder onCommit(final Consumer f) {
return this;
}
/**
* Helper function to chain consumers together or return the new one if the current consumer
* isn't set.
*
* @param currentConsumer the current consumer, which may be null
* @param consumer the new consumer to chain with the current one.
* @param
* @return the chained consumer (or the new consumer if there previously wasn't one around)
*/
private Consumer chainConsumers(final Consumer currentConsumer, final Consumer consumer) {
if (currentConsumer != null) {
return currentConsumer.andThen(consumer);
}
return consumer;
}
private BiConsumer chainConsumers(final BiConsumer currentConsumer, final BiConsumer consumer) {
if (currentConsumer != null) {
return currentConsumer.andThen(consumer);
}
return consumer;
}
}