@Nonnull
  public PSSpan readSpanFromXML (@Nonnull final IMicroElement eSpan)
  {
    final PSSpan ret = new PSSpan ();

    eSpan.forAllAttributes ( (sNS, sAttrName, sVal) -> {
      final String sAttrValue = _getAttributeValue (sVal);
      if (sAttrName.equals (CSchematronXML.ATTR_CLASS))
        ret.setClazz (sAttrValue);
      else
        ret.addForeignAttribute (sAttrName, sAttrValue);
    });

    eSpan.forAllChildren (aSpanChild -> {
      switch (aSpanChild.getType ())
      {
        case TEXT:
          ret.addText (((IMicroText) aSpanChild).getNodeValue ());
          break;
        case ELEMENT:
          final IMicroElement eElement = (IMicroElement) aSpanChild;
          if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
          {
            _warn (ret, "Unsupported Schematron element '" + eElement.getLocalName () + "'");
          }
          else
            ret.addForeignElement (eElement.getClone ());

          break;
        case COMMENT:
          // Ignore comments
          break;
        default:
          _warn (ret, "Unsupported child node: " + aSpanChild);
      }
    });
    return ret;
  }

@
Nonnull
public
PSSpan
readSpanFromXML
(
@
Nonnull
final
IMicroElement
eSpan
)
{
final
PSSpan
ret
=
new
PSSpan
(
)
;
eSpan
.
forAllAttributes
(
(
sNS
,
sAttrName
,
sVal
)
->
{
final
String
sAttrValue
=
_getAttributeValue
(
sVal
)
;
if
(
sAttrName
.
equals
(
CSchematronXML
.
ATTR_CLASS
)
)
ret
.
setClazz
(
sAttrValue
)
;
else
ret
.
addForeignAttribute
(
sAttrName
,
sAttrValue
)
;
}
)
;
eSpan
.
forAllChildren
(
aSpanChild
->
{
switch
(
aSpanChild
.
getType
(
)
)
{
case
TEXT
:
ret
.
addText
(
(
(
IMicroText
)
aSpanChild
)
.
getNodeValue
(
)
)
;
break
;
case
ELEMENT
:
final
IMicroElement
eElement
=
(
IMicroElement
)
aSpanChild
;
if
(
CSchematron
.
NAMESPACE_SCHEMATRON
.
equals
(
eElement
.
getNamespaceURI
(
)
)
)
{
_warn
(
ret
,
"Unsupported Schematron element '"
+
eElement
.
getLocalName
(
)
+
"'"
)
;
}
else
ret
.
addForeignElement
(
eElement
.
getClone
(
)
)
;
break
;
case
COMMENT
:
// Ignore comments
break
;
default
:
_warn
(
ret
,
"Unsupported child node: "
+
aSpanChild
)
;
}
}
)
;
return
ret
;
}

Read a <span> element

@param eSpan
The source micro element. Never null.
@return The created domain object. May not be null.


@Nonnull
  public PSTitle readTitleFromXML (@Nonnull final IMicroElement eTitle)
  {
    final PSTitle ret = new PSTitle ();

    eTitle.forAllAttributes ( (sNS, sAttrName, sVal) -> {
      final String sAttrValue = _getAttributeValue (sVal);
      _warn (ret, "Unsupported attribute '" + sAttrName + "'='" + sAttrValue + "'");
    });

    eTitle.forAllChildren (aTitleChild -> {
      switch (aTitleChild.getType ())
      {
        case TEXT:
          ret.addText (((IMicroText) aTitleChild).getNodeValue ());
          break;
        case ELEMENT:
          final IMicroElement eElement = (IMicroElement) aTitleChild;
          if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
          {
            final String sLocalName = eElement.getLocalName ();
            if (sLocalName.equals (CSchematronXML.ELEMENT_DIR))
              ret.addDir (readDirFromXML (eElement));
            else
              _warn (ret, "Unsupported Schematron element '" + sLocalName + "'");
          }
          else
            _warn (ret, "Unsupported namespace URI '" + eElement.getNamespaceURI () + "'");

          break;
        case COMMENT:
          // Ignore comments
          break;
        default:
          _warn (ret, "Unsupported child node: " + aTitleChild);
      }
    });
    return ret;
  }

@
Nonnull
public
PSTitle
readTitleFromXML
(
@
Nonnull
final
IMicroElement
eTitle
)
{
final
PSTitle
ret
=
new
PSTitle
(
)
;
eTitle
.
forAllAttributes
(
(
sNS
,
sAttrName
,
sVal
)
->
{
final
String
sAttrValue
=
_getAttributeValue
(
sVal
)
;
_warn
(
ret
,
"Unsupported attribute '"
+
sAttrName
+
"'='"
+
sAttrValue
+
"'"
)
;
}
)
;
eTitle
.
forAllChildren
(
aTitleChild
->
{
switch
(
aTitleChild
.
getType
(
)
)
{
case
TEXT
:
ret
.
addText
(
(
(
IMicroText
)
aTitleChild
)
.
getNodeValue
(
)
)
;
break
;
case
ELEMENT
:
final
IMicroElement
eElement
=
(
IMicroElement
)
aTitleChild
;
if
(
CSchematron
.
NAMESPACE_SCHEMATRON
.
equals
(
eElement
.
getNamespaceURI
(
)
)
)
{
final
String
sLocalName
=
eElement
.
getLocalName
(
)
;
if
(
sLocalName
.
equals
(
CSchematronXML
.
ELEMENT_DIR
)
)
ret
.
addDir
(
readDirFromXML
(
eElement
)
)
;
else
_warn
(
ret
,
"Unsupported Schematron element '"
+
sLocalName
+
"'"
)
;
}
else
_warn
(
ret
,
"Unsupported namespace URI '"
+
eElement
.
getNamespaceURI
(
)
+
"'"
)
;
break
;
case
COMMENT
:
// Ignore comments
break
;
default
:
_warn
(
ret
,
"Unsupported child node: "
+
aTitleChild
)
;
}
}
)
;
return
ret
;
}

Read a <title> element

@param eTitle
The source micro element. Never null.
@return The created domain object. May not be null.


@Nonnull
  public PSValueOf readValueOfFromXML (@Nonnull final IMicroElement eValueOf)
  {
    final PSValueOf ret = new PSValueOf ();

    eValueOf.forAllAttributes ( (sNS, sAttrName, sVal) -> {
      final String sAttrValue = _getAttributeValue (sVal);
      if (sAttrName.equals (CSchematronXML.ATTR_SELECT))
        ret.setSelect (sAttrValue);
      else
        ret.addForeignAttribute (sAttrName, sAttrValue);
    });

    eValueOf.forAllChildElements (eValueOfChild -> {
      if (CSchematron.NAMESPACE_SCHEMATRON.equals (eValueOfChild.getNamespaceURI ()))
      {
        _warn (ret, "Unsupported Schematron element '" + eValueOfChild.getLocalName () + "'");
      }
      else
        _warn (ret, "Unsupported namespace URI '" + eValueOfChild.getNamespaceURI () + "'");
    });
    return ret;
  }

@
Nonnull
public
PSValueOf
readValueOfFromXML
(
@
Nonnull
final
IMicroElement
eValueOf
)
{
final
PSValueOf
ret
=
new
PSValueOf
(
)
;
eValueOf
.
forAllAttributes
(
(
sNS
,
sAttrName
,
sVal
)
->
{
final
String
sAttrValue
=
_getAttributeValue
(
sVal
)
;
if
(
sAttrName
.
equals
(
CSchematronXML
.
ATTR_SELECT
)
)
ret
.
setSelect
(
sAttrValue
)
;
else
ret
.
addForeignAttribute
(
sAttrName
,
sAttrValue
)
;
}
)
;
eValueOf
.
forAllChildElements
(
eValueOfChild
->
{
if
(
CSchematron
.
NAMESPACE_SCHEMATRON
.
equals
(
eValueOfChild
.
getNamespaceURI
(
)
)
)
{
_warn
(
ret
,
"Unsupported Schematron element '"
+
eValueOfChild
.
getLocalName
(
)
+
"'"
)
;
}
else
_warn
(
ret
,
"Unsupported namespace URI '"
+
eValueOfChild
.
getNamespaceURI
(
)
+
"'"
)
;
}
)
;
return
ret
;
}

Read a <value-of> element

@param eValueOf
The source micro element. Never null.
@return The created domain object. May not be null.


@Nonnull
  @ReturnsMutableCopy
  public static MapBasedNamespaceContext createNamespaceMapping (@Nonnull final PSSchema aSchema)
  {
    final MapBasedNamespaceContext ret = new MapBasedNamespaceContext ();
    ret.addDefaultNamespaceURI (CSchematron.NAMESPACE_SCHEMATRON);
    for (final PSNS aItem : aSchema.getAllNSs ())
      ret.addMapping (aItem.getPrefix (), aItem.getUri ());
    return ret;
  }

@ Nonnull @ ReturnsMutableCopy public static MapBasedNamespaceContext createNamespaceMapping ( @ Nonnull final PSSchema aSchema ) { final MapBasedNamespaceContext ret = new MapBasedNamespaceContext ( ) ; ret . addDefaultNamespaceURI ( CSchematron . NAMESPACE_SCHEMATRON ) ; for ( final PSNS aItem : aSchema . getAllNSs ( ) ) ret . addMapping ( aItem . getPrefix ( ) , aItem . getUri ( ) ) ; return ret ; }

Helper method to extract the namespace mapping from the provided
Schematron.

@param aSchema
The schema to extract the namespace context from. May not be
null.
@return A non-null but maybe empty namespace context

Helper method to extract the namespace mapping from the provided Schematron .


private <T> CompletionStage<T> regex(final Http.RequestHeader requestHeader,
                                         final DeadboltHandler deadboltHandler,
                                         final Optional<String> content,
                                         final String[] values,
                                         final int valueIndex,
                                         final ConstraintMode mode,
                                         final boolean invert,
                                         final Function<Http.RequestHeader, CompletionStage<T>> pass,
                                         final TriFunction<Http.RequestHeader, DeadboltHandler, Optional<String>, CompletionStage<T>> fail,
                                         final ConstraintPoint constraintPoint)
    {
        return CompletableFuture.completedFuture(patternCache.apply(values[valueIndex]))
                                .thenCombine(getSubject(requestHeader,
                                                             deadboltHandler),
                                             (patternValue, subject) ->
                                                     F.Tuple(subject._1.isPresent() ? analyzer.checkRegexPattern(subject._1,
                                                                                Optional.ofNullable(patternValue))
                                                                         : invert, subject._2)) // this is a little clumsy - it means no subject + invert is still denied

                                .thenCompose(hasPassed -> (invert ? !hasPassed._1 : hasPassed._1) ? (successCallAgain(mode, values, valueIndex) ? regex(hasPassed._2,
                                                                                deadboltHandler,
                                                                                content,
                                                                                values,
                                                                                valueIndex + 1,
                                                                                mode,
                                                                                invert,
                                                                                pass,
                                                                                fail,
                                                                                constraintPoint)
                                                                                : pass(hasPassed._2,
                                                                                deadboltHandler,
                                                                                pass,
                                                                                constraintPoint,
                                                                                "pattern - regex"))
                                                                                : (failCallAgain(mode, values, valueIndex) ? regex(hasPassed._2,
                                                                                deadboltHandler,
                                                                                content,
                                                                                values,
                                                                                valueIndex + 1,
                                                                                mode,
                                                                                invert,
                                                                                pass,
                                                                                fail,
                                                                                constraintPoint)
                                                                                : fail.apply(hasPassed._2,
                                                                                deadboltHandler,
                                                                                content)));
    }

Checks access to the resource based on the regex

@param requestHeader             the HTTP request header
@param deadboltHandler the Deadbolt handler
@param invert          if true, invert the application of the constraint
@return the necessary result


private Http.RequestHeader markAsAuthorised(final Http.RequestHeader request)
    {
        this.authorised = true;
        return request.addAttr(ACTION_AUTHORISED,
                     true);
    }

private Http . RequestHeader markAsAuthorised ( final Http . RequestHeader request ) { this . authorised = true ; return request . addAttr ( ACTION_AUTHORISED , true ) ; }

Marks the current action as authorised.  This allows method-level annotations to override controller-level annotations.

@param request the request

Marks the current action as authorised . This allows method - level annotations to override controller - level annotations .


protected static boolean isAuthorised(final Http.RequestHeader request)
    {
        return request.attrs().getOptional(ACTION_AUTHORISED).orElse(false);
    }

protected static boolean isAuthorised ( final Http . RequestHeader request ) { return request . attrs ( ) . getOptional ( ACTION_AUTHORISED ) . orElse ( false ) ; }

Checks if an action is authorised.  This allows controller-level annotations to cede control to method-level annotations.

@param request the request
@return true if a more-specific annotation has authorised access, otherwise false

Checks if an action is authorised . This allows controller - level annotations to cede control to method - level annotations .


protected Http.RequestHeader defer(final Http.RequestHeader request,
                         final AbstractDeadboltAction<T> action)
    {
        if (action != null)
        {
            LOGGER.info("Deferring action [{}]",
                        this.getClass().getName());
            return request.addAttr(ACTION_DEFERRED,
                         action);
        }
        return request;
    }

protected
Http
.
RequestHeader
defer
(
final
Http
.
RequestHeader
request
,
final
AbstractDeadboltAction
<
T
>
action
)
{
if
(
action
!=
)
{
LOGGER
.
info
(
"Deferring action [{}]"
,
this
.
getClass
(
)
.
getName
(
)
)
;
return
request
.
addAttr
(
ACTION_DEFERRED
,
action
)
;
}
return
request
;
}

Defer execution until a later point.

@param request    the request
@param action the action to defer


@SuppressWarnings("unchecked")
    public F.Tuple<AbstractDeadboltAction<?>, Http.RequestHeader> getDeferredAction(final Http.RequestHeader request)
    {
        return request.attrs().getOptional(ACTION_DEFERRED).map(action -> {
            action.delegate = this;
            return F.<AbstractDeadboltAction<?>, Http.RequestHeader>Tuple(action, request.removeAttr(ACTION_DEFERRED).addAttr(IGNORE_DEFERRED_FLAG, true));
        }).orElseGet(() -> F.Tuple(null, request));
    }

@ SuppressWarnings ( "unchecked" ) public F . Tuple < AbstractDeadboltAction < ? > , Http . RequestHeader > getDeferredAction ( final Http . RequestHeader request ) { return request . attrs ( ) . getOptional ( ACTION_DEFERRED ) . map ( action -> { action . delegate = this ; return F . < AbstractDeadboltAction < ? > , Http . RequestHeader > Tuple ( action , request . removeAttr ( ACTION_DEFERRED ) . addAttr ( IGNORE_DEFERRED_FLAG , true ) ) ; } ) . orElseGet ( ( ) -> F . Tuple ( null , request ) ) ; }

Get the deferred action from the request.

@param request the request
@return a tuple containing the deferred action (or null if it doesn't exist) and the cleaned up request you should pass on

Get the deferred action from the request .


protected CompletionStage<Result> authorizeAndExecute(final Http.RequestHeader request)
    {
        if(constraintAnnotationMode != ConstraintAnnotationMode.AND)
        {
            // In AND mode we don't mark an action as authorised because we want ALL (remaining) constraints to be evaluated as well!
            return delegate.call((Http.Request)markAsAuthorised(request));
        }
        return delegate.call((Http.Request)request);
    }

Add a flag to the request to indicate the action has passed the constraint
and call the delegate.

@param request the request
@return the result

Add a flag to the request to indicate the action has passed the constraint and call the delegate .


private static boolean deadboltActionLeftInActionChain(final Action<?> action) {
        if(action != null) {
            if(action.delegate instanceof AbstractDeadboltAction) {
                return true; // yes, there is at least one deadbolt action remaining
            }
            // action.delegate wasn't a deadbolt action, let's check the next one in the chain
            return deadboltActionLeftInActionChain(action.delegate);
        }
        return false;
    }

Recursive method to determine if there is another deadbolt action further down the action chain


public List<String> getRoleNames(final Optional<? extends Subject> subjectOption)
    {
        final List<String> roleNames = new ArrayList<>();
        subjectOption.ifPresent(subject ->
                                {
                                    final List<? extends Role> roles = subject.getRoles();
                                    if (roles != null)
                                    {
                                        roleNames.addAll(roles.stream()
                                                              .filter(Objects::nonNull)
                                                              .map(Role::getName)
                                                              .collect(Collectors.toList()));
                                    }
                                });

        return roleNames;
    }

public List < String > getRoleNames ( final Optional < ? extends Subject > subjectOption ) { final List < String > roleNames = new ArrayList <> ( ) ; subjectOption . ifPresent ( subject -> { final List < ? extends Role > roles = subject . getRoles ( ) ; if ( roles != null ) { roleNames . addAll ( roles . stream ( ) . filter ( Objects :: nonNull ) . map ( Role :: getName ) . collect ( Collectors . toList ( ) ) ) ; } } ) ; return roleNames ; }

Gets the role name of each role held.

@param subjectOption an option for the subject
@return a non-null list containing all role names


public boolean hasRole(final Optional<? extends Subject> subjectOption,
                           final String roleName)
    {
        return getRoleNames(subjectOption).contains(roleName);
    }

public boolean hasRole ( final Optional < ? extends Subject > subjectOption , final String roleName ) { return getRoleNames ( subjectOption ) . contains ( roleName ) ; }

Check if the subject has the given role.

@param subjectOption an option for the subject
@param roleName      the name of the role
@return true iff the subject has the role represented by the role name

Check if the subject has the given role .


public FilterFunction subjectPresent(final Optional<String> content)
    {
        return (Http.RequestHeader requestHeader,
                DeadboltHandler handler,
                Function<Http.RequestHeader, CompletionStage<Result>> next) ->
                beforeAuthCheckCache.apply(handler, requestHeader, content)
                       .thenCompose(maybePreAuth -> maybePreAuth._1.map(preAuthResult -> (CompletionStage<Result>) CompletableFuture.completedFuture(preAuthResult))
                                                                .orElseGet(() -> constraintLogic.subjectPresent(maybePreAuth._2,
                                                                                handler,
                                                                                content,
                                                                                (rh, hdlr, cntent) -> next.apply(rh),
                                                                                (rh, hdlr, cntent) -> hdlr.onAuthFailure(rh,
                                                                                cntent),
                                                                                ConstraintPoint.FILTER)));
    }

public FilterFunction subjectPresent ( final Optional < String > content ) { return ( Http . RequestHeader requestHeader , DeadboltHandler handler , Function < Http . RequestHeader , CompletionStage < Result > > next ) -> beforeAuthCheckCache . apply ( handler , requestHeader , content ) . thenCompose ( maybePreAuth -> maybePreAuth . _1 . map ( preAuthResult -> ( CompletionStage < Result > ) CompletableFuture . completedFuture ( preAuthResult ) ) . orElseGet ( ( ) -> constraintLogic . subjectPresent ( maybePreAuth . _2 , handler , content , ( rh , hdlr , cntent ) -> next . apply ( rh ) , ( rh , hdlr , cntent ) -> hdlr . onAuthFailure ( rh , cntent ) , ConstraintPoint . FILTER ) ) ) ; }

A constraint that requires a subject to be present.

@param content is passed to {@link DeadboltHandler#onAuthFailure(Http.RequestHeader, Optional)} if the authorization fails
@return a function that wraps the constraint
@see ConstraintLogic#subjectPresent(Http.RequestHeader, DeadboltHandler, Optional, TriFunction, TriFunction, ConstraintPoint)

A constraint that requires a subject to be present .


public static String[] roles(final Role... roles)
    {
        final List<String> names = new ArrayList<>(roles.length);
        for (Role role : roles)
        {
            names.add(role.getName());
        }
        return names.toArray(new String[names.size()]);
    }

public static String [ ] roles ( final Role ... roles ) { final List < String > names = new ArrayList <> ( roles . length ) ; for ( Role role : roles ) { names . add ( role . getName ( ) ) ; } return names . toArray ( new String [ names . size ( ) ] ) ; }

Converts the roles into a String array.

@param roles the roles
@return the roles as an array of strings

Converts the roles into a String array .


public static String[] permissions(final Permission... permissions)
    {
        final List<String> values = new ArrayList<>(permissions.length);
        for (Permission permission : permissions)
        {
            values.add(permission.getValue());
        }
        return values.toArray(new String[values.size()]);
    }

public static String [ ] permissions ( final Permission ... permissions ) { final List < String > values = new ArrayList <> ( permissions . length ) ; for ( Permission permission : permissions ) { values . add ( permission . getValue ( ) ) ; } return values . toArray ( new String [ values . size ( ) ] ) ; }

Converts the permissions into a String array.

@param permissions the permissions
@return the permissions as an array of strings

Converts the permissions into a String array .


public static List<String[]> allOfGroup(final String... args)
    {
        return Collections.singletonList(args == null ? new String[0] : args);
    }

public static List < String [ ] > allOfGroup ( final String ... args ) { return Collections . singletonList ( args == null ? new String [ 0 ] : args ) ; }

Converts the arguments into a String array wrapped in a list.

@param args the arguments
@return the arguments as an array within a list

Converts the arguments into a String array wrapped in a list .


public boolean viewRestrict(final List<String[]> roles,
                                final DeadboltHandler handler,
                                final Optional<String> content,
                                final long timeoutInMillis,
                                final Http.RequestHeader requestHeader) throws Throwable
    {
        boolean allowed;
        try
        {
            allowed = constraintLogic.restrict(requestHeader,
                                               handler(handler),
                                               content,
                                               () -> roles,
                                               rh -> CompletableFuture.completedFuture(Boolean.TRUE),
                                               (rh, dh, cnt) -> CompletableFuture.completedFuture(Boolean.FALSE),
                                               ConstraintPoint.TEMPLATE)
                                     .toCompletableFuture()
                                     .get(timeoutInMillis,
                                          TimeUnit.MILLISECONDS);

        }
        catch (TimeoutException e)
        {
            allowed = timeoutHandler.apply(timeoutInMillis,
                                           e);
        }
        return allowed;
    }

public boolean viewRestrict ( final List < String [ ] > roles , final DeadboltHandler handler , final Optional < String > content , final long timeoutInMillis , final Http . RequestHeader requestHeader ) throws Throwable { boolean allowed ; try { allowed = constraintLogic . restrict ( requestHeader , handler ( handler ) , content , ( ) -> roles , rh -> CompletableFuture . completedFuture ( Boolean . TRUE ) , ( rh , dh , cnt ) -> CompletableFuture . completedFuture ( Boolean . FALSE ) , ConstraintPoint . TEMPLATE ) . toCompletableFuture ( ) . get ( timeoutInMillis , TimeUnit . MILLISECONDS ) ; } catch ( TimeoutException e ) { allowed = timeoutHandler . apply ( timeoutInMillis , e ) ; } return allowed ; }

Used for restrict tags in the template.

@param roles a list of String arrays.  Within an array, the roles are ANDed.  The arrays in the list are OR'd.
@return true if the view can be accessed, otherwise false

Used for restrict tags in the template .


static CoderResult overflow(CharBuffer input, int i, CharBuffer output, int j) {
        input.position(i - input.arrayOffset());
        output.position(j - output.arrayOffset());
        return CoderResult.OVERFLOW;
    }

static CoderResult overflow ( CharBuffer input , int i , CharBuffer output , int j ) { input . position ( i - input . arrayOffset ( ) ) ; output . position ( j - output . arrayOffset ( ) ) ; return CoderResult . OVERFLOW ; }

Internal helper method to properly position buffers after encoding up
until an overflow.

@param input the input buffer
@param i the array offset in the input buffer (translated to position)
@param output the output buffer
@param j the array offset in the output buffer (translated to position)
@return CoderResult.OVERFLOW

Internal helper method to properly position buffers after encoding up until an overflow .


static CoderResult underflow(CharBuffer input, int i, CharBuffer output, int j) {
        input.position(i - input.arrayOffset());
        output.position(j - output.arrayOffset());
        return CoderResult.UNDERFLOW;
    }

static CoderResult underflow ( CharBuffer input , int i , CharBuffer output , int j ) { input . position ( i - input . arrayOffset ( ) ) ; output . position ( j - output . arrayOffset ( ) ) ; return CoderResult . UNDERFLOW ; }

Internal helper method to properly position buffers after encoding up
until an underflow.

@param input the input buffer
@param i the array offset in the input buffer (translated to position)
@param output the output buffer
@param j the array offset in the output buffer (translated to position)
@return CoderResult.UNDERFLOW

Internal helper method to properly position buffers after encoding up until an underflow .


ASCIIBits set(int min, int max) {
        // There are faster bit-twiddling tricks to accomplish the same
        // thing as below.  Minor optimization for later.
        int i=min;
        for (int n = Math.min(max,63) ; i<=n ; ++i) {
            _lowerMask |= (1L << i);
        }
        for ( ; i<=max ; ++i) {
            _upperMask |= (1L << i);
        }
        return this;
    }

Sets a range of characters to 1s in the masks.

@param min the minimum (inclusive).
@param max the maximum (inclusive).
@return {@code this}

Sets a range of characters to 1s in the masks .


static String encode(Encoder encoder, String str) {
        if (str == null) {
            // consistent with String.valueOf(...) use "null" for null.
            str = "null";
        }

        // quick pass--see if we need to actually encode anything, if not
        // return the value unchanged.
        final int n = str.length();
        int j = encoder.firstEncodedOffset(str, 0, n);

        if (j == n) {
            return str;
        }

        // otherwise, we need to encode.  We use a buffer to avoid
        // excessive memory allocation for these calls.  Note: this means that
        // an encoder implementation must NEVER call this method internally.
        return new Buffer().encode(encoder, str, j);
    }

Core encoding loop shared by public methods.  It first uses the
encoder to scan the input for characters that need encoding.  If
no characters require encoding, the input string is returned.
Otherwise a buffer is used to encode the remainder
of the input.

@param encoder the encoder to use
@param str the string to encode
@return the input string encoded with the provided encoder.

Core encoding loop shared by public methods . It first uses the encoder to scan the input for characters that need encoding . If no characters require encoding the input string is returned . Otherwise a buffer is used to encode the remainder of the input .


static void encode(Encoder encoder, Writer out, String str)
        throws IOException
    {
        if (str == null) {
            // consistent with String.valueOf(...) use "null" for null.
            str = "null";
        }

        // quick pass--see if we need to actually encode anything, if not
        // return the value unchanged.
        final int n = str.length();
        int j = encoder.firstEncodedOffset(str, 0, n);

        if (j == n) {
            out.write(str);
            return;
        }

        // otherwise, we need to encode.  We use a buffer to avoid
        // excessive memory allocation for these calls.  Note: this means that
        // an encoder implementation must NEVER call this method internally.
        new Buffer().encode(encoder, out, str, j);
    }

Core encoding loop shared by public methods.  It first uses the
encoder to scan the input for characters that need encoding.  If no
characters require encoding, the input string is written directly to
the writer.  Otherwise a buffer is used to encode the
remainder of the input to the buffers.  This version saves a wrapping
in an String.

@param encoder the encoder to use
@param out the writer for the encoded output
@param str the string to encode
@throws IOException if thrown by the writer

Core encoding loop shared by public methods . It first uses the encoder to scan the input for characters that need encoding . If no characters require encoding the input string is written directly to the writer . Otherwise a buffer is used to encode the remainder of the input to the buffers . This version saves a wrapping in an String .


private static <T extends Encoder> T map(String name, T encoder) {
        Encoder old = ENCODERS_MAP.put(name, encoder);
        assert old == null;
        return encoder;
    }

private static < T extends Encoder > T map ( String name , T encoder ) { Encoder old = ENCODERS_MAP . put ( name , encoder ) ; assert old == null ; return encoder ; }

Internal method to setup and map encoder singletons.

@param name -- name of the encoder (one of the constants above)
@param encoder -- the encoder singleton instance
@param <T> the encoder type
@return the encoder argument.

Internal method to setup and map encoder singletons .


public static Encoder forName(String contextName) throws NullPointerException, UnsupportedContextException {
        if (contextName == null) {
            throw new NullPointerException();
        }
        Encoder encoder = ENCODERS_MAP.get(contextName);
        if (encoder == null) {
            throw new UnsupportedContextException(contextName);
        }
        return encoder;
    }

public static Encoder forName ( String contextName ) throws NullPointerException , UnsupportedContextException { if ( contextName == null ) { throw new NullPointerException ( ) ; } Encoder encoder = ENCODERS_MAP . get ( contextName ) ; if ( encoder == null ) { throw new UnsupportedContextException ( contextName ) ; } return encoder ; }

Returns a new instance of an Encoder for the specified context. The
returned instance is thread-safe.

@param contextName the context name (one of the String constants defined
in this class)
@return an encoder for the specified context.
@throws NullPointerException if {@code contextName} is null
@throws UnsupportedContextException if {@code contextName} is not
recognized.

Returns a new instance of an Encoder for the specified context . The returned instance is thread - safe .


static int append(char[] src, char[] out, int j) {
        System.arraycopy(src, 0, out, j, src.length);
        return j + src.length;
    }

static int append ( char [ ] src , char [ ] out , int j ) { System . arraycopy ( src , 0 , out , j , src . length ) ; return j + src . length ; }

Appends a source array verbatim to the output array. Caller must insure
there is enough space in the array for the output.

@param src the characters to copy
@param out the output buffer
@param j the offset where to write in the output buffer
@return {@code j + src.length}

Appends a source array verbatim to the output array . Caller must insure there is enough space in the array for the output .


public String encode(String str) {
        if (str == null) {
            str = "null";
        }

        int n = str.length();
        int j = _first.firstEncodedOffset(str, 0, n);
        if (j == n) {
            // string is unchanged after encoding with the first encoder
            return Encode.encode(_last, str);
        }

        final int remaining = n - j;
        final int m = j + _first.maxEncodedLength(n);
        CharBuffer input = CharBuffer.allocate(m);
        str.getChars(0, j, input.array(), 0);
        str.getChars(j, n, input.array(), m - remaining);

        input.limit(m).position(m - remaining);
        CharBuffer tmp = input.duplicate();
        tmp.position(j);

        CoderResult cr = _first.encode(input, tmp, true);
        assert cr.isUnderflow() : "maxEncodedLength was incorrect";

        CharBuffer output = CharBuffer.allocate(_last.maxEncodedLength(tmp.position()));
        tmp.flip();

        cr = _last.encode(tmp, output, true);
        assert cr.isUnderflow() : "maxEncodedLength was incorrect";

        return new String(output.array(), 0, output.position());
    }

Encodes an input string to an output string.

@param str the string to encode
@return the encoded string.

Encodes an input string to an output string .


private void flushBufferToWriter() throws IOException {
        _out.write(_buffer.array(), 0, _buffer.position());
        _buffer.clear();
    }

private void flushBufferToWriter ( ) throws IOException { _out . write ( _buffer . array ( ) , 0 , _buffer . position ( ) ) ; _buffer . clear ( ) ; }

Flushes the contents of the buffer to the writer and resets the buffer to make room for more input.

@throws IOException thrown by the wrapped output.

Flushes the contents of the buffer to the writer and resets the buffer to make room for more input .


private void flushLeftOver(CharBuffer input) throws IOException {
        if (!_hasLeftOver) {
            return;
        }

        for (;;) {
            if (input != null && input.hasRemaining()) {
                _leftOverBuffer.put(input.get());
            }

            _leftOverBuffer.flip();
            CoderResult cr = _encoder.encode(_leftOverBuffer, _buffer, input == null);

            if (cr.isUnderflow()) {
                if (_leftOverBuffer.hasRemaining()) {
                    _leftOverBuffer.compact();
                } else {
                    break;
                }
            }
            if (cr.isOverflow()) {
                flushBufferToWriter();
            }
        }

        _hasLeftOver = false;
        _leftOverBuffer.clear();
    }

private void flushLeftOver ( CharBuffer input ) throws IOException { if ( ! _hasLeftOver ) { return ; } for ( ; ; ) { if ( input != null && input . hasRemaining ( ) ) { _leftOverBuffer . put ( input . get ( ) ) ; } _leftOverBuffer . flip ( ) ; CoderResult cr = _encoder . encode ( _leftOverBuffer , _buffer , input == null ) ; if ( cr . isUnderflow ( ) ) { if ( _leftOverBuffer . hasRemaining ( ) ) { _leftOverBuffer . compact ( ) ; } else { break ; } } if ( cr . isOverflow ( ) ) { flushBufferToWriter ( ) ; } } _hasLeftOver = false ; _leftOverBuffer . clear ( ) ; }

Flushes the left-over buffer. Characters from the input buffer are used to add more data to the _leftOverBuffer in order to
make the flush happen.

@param input the next input to encode, or null if at end of file.
@throws IOException from the underlying writer.

Flushes the left - over buffer . Characters from the input buffer are used to add more data to the _leftOverBuffer in order to make the flush happen .


public Flowable<ReactiveSensorEvent> observeSensor(int sensorType, final int samplingPeriodInUs,
      final Handler handler, final BackpressureStrategy strategy) {

    if (!hasSensor(sensorType)) {
      String format = "Sensor with id = %d is not available on this device";
      String message = String.format(Locale.getDefault(), format, sensorType);
      return Flowable.error(new SensorNotFoundException(message));
    }

    final Sensor sensor = sensorManager.getDefaultSensor(sensorType);
    final SensorEventListenerWrapper wrapper = new SensorEventListenerWrapper();
    final SensorEventListener listener = wrapper.create();

    return Flowable.create(new FlowableOnSubscribe<ReactiveSensorEvent>() {
      @Override public void subscribe(final FlowableEmitter<ReactiveSensorEvent> emitter)
          throws Exception {

        wrapper.setEmitter(emitter);

        if (handler == null) {
          sensorManager.registerListener(listener, sensor, samplingPeriodInUs);
        } else {
          sensorManager.registerListener(listener, sensor, samplingPeriodInUs, handler);
        }
      }
    }, strategy).doOnCancel(new Action() {
      @Override public void run() throws Exception {
        sensorManager.unregisterListener(listener);
      }
    });
  }

Returns RxJava Observable, which allows to monitor hardware sensors
as a stream of ReactiveSensorEvent object with defined sampling period

@param sensorType sensor type from Sensor class from Android SDK
@param samplingPeriodInUs sampling period in microseconds,
@param handler the Handler the sensor events will be delivered to, use default if it is null
you can use predefined values from SensorManager class with prefix SENSOR_DELAY
@param strategy BackpressureStrategy for RxJava 2 Flowable type
@return RxJava Observable with ReactiveSensorEvent

Returns RxJava Observable which allows to monitor hardware sensors as a stream of ReactiveSensorEvent object with defined sampling period


private String getText(JsonNode node, String propertyName) {
        JsonNode childNode = node.get(propertyName);
        if (childNode == null) {
            return null;
        }
        return childNode.asText();
    }

private String getText ( JsonNode node , String propertyName ) { JsonNode childNode = node . get ( propertyName ) ; if ( childNode == null ) { return null ; } return childNode . asText ( ) ; }

Get the text from child node with the given name.  Returns null if child node does not exist.

@param node         Node to search
@param propertyName Name of the child node
@return The text value of the child node

Get the text from child node with the given name . Returns null if child node does not exist .


public Result execute(Query query) throws SonarBreakException, IOException {
        URL queryURL = buildURL(sonarURL, query);
        log.debug("Built a sonar query url of: " + queryURL.toString());

        if (!isURLAvailable(sonarURL, SONAR_CONNECTION_RETRIES)) {
            throw new SonarBreakException(String.format("Unable to get a valid response after %d tries", SONAR_CONNECTION_RETRIES));
        }

        return fetchSonarStatusWithRetries(queryURL, query.getVersion());
    }

Execute the given query on the specified sonar server.

@param query The query specifying the project and version of the build
@return Result fetched from sonar
@throws SonarBreakException If there is an issues communicating with sonar
@throws IOException         If the url is invalid

Execute the given query on the specified sonar server .


protected static URL buildURL(URL sonarURL, Query query) throws MalformedURLException, IllegalArgumentException {
        if (query.getSonarKey() == null || query.getSonarKey().length() == 0) {
            throw new IllegalArgumentException("No resource specified in the Query");
        }
        String sonarPathWithResource = String.format(SONAR_FORMAT_PATH, query.getSonarKey());
        return new URL(sonarURL, sonarPathWithResource);
    }

protected
static
URL
buildURL
(
URL
sonarURL
,
Query
query
)
throws
MalformedURLException
,
IllegalArgumentException
{
if
(
query
.
getSonarKey
(
)
==
||
query
.
getSonarKey
(
)
.
length
(
)
==
0
)
{
throw
new
IllegalArgumentException
(
"No resource specified in the Query"
)
;
}
String
sonarPathWithResource
=
String
.
format
(
SONAR_FORMAT_PATH
,
query
.
getSonarKey
(
)
)
;
return
new
URL
(
sonarURL
,
sonarPathWithResource
)
;
}

Creates a url for the specified quality gate query

@param sonarURL The sonar server we will be querying
@param query    Holds details on the query we want to make
@return A URL object representing the query
@throws MalformedURLException    If the sonar url is not valid
@throws IllegalArgumentException If the sonar key is not valid


private Result fetchSonarStatusWithRetries(URL queryURL, String version) throws IOException, SonarBreakException {
        DateTime oneMinuteAgo = DateTime.now().minusSeconds(sonarLookBackSeconds);
        DateTime waitUntil = DateTime.now().plusSeconds(waitForProcessingSeconds);
        do {
            // If this is the first time the job is running on sonar the URL might not be available.  Return null and wait.
            if (isURLAvailable(queryURL, 1)) {
                Result result = fetchSonarStatus(queryURL);
                if (result.getVersion().equals(version) && result.getDatetime().isAfter(oneMinuteAgo)) {
                    log.debug("Found a sonar job run that matches version and in the correct time frame");
                    return result;
                }
                String message = String.format("Sleeping while waiting for sonar to process job.  Target Version: %s.  " +
                                "Sonar reporting Version: %s.  Looking back until: %s  Last result time: %s", version,
                        result.getVersion(), oneMinuteAgo.toString(), result.getDatetime().toString());
                log.debug(message);
            } else {
                log.debug(String.format("Query url not available yet: %s", queryURL));
            }
            try {
                Thread.sleep(SONAR_PROCESSING_WAIT_TIME);
            } catch (InterruptedException e) {
                // Do nothing
            }
        } while (!waitUntil.isBeforeNow());

        String message = String.format("Timed out while waiting for Sonar.  Waited %d seconds.  This time can be extended " +
                "using the \"waitForProcessingSeconds\" configuration parameter.", waitForProcessingSeconds);
        throw new SonarBreakException(message);
    }

Get the status from sonar for the currently executing build.  This waits for sonar to complete its processing
before returning the results.

@param queryURL The sonar URL to get the results from
@param version  The current project version number
@return Matching result object for this build
@throws IOException
@throws SonarBreakException

Get the status from sonar for the currently executing build . This waits for sonar to complete its processing before returning the results .


private Result fetchSonarStatus(URL queryURL) throws IOException, SonarBreakException {
        InputStream in = null;
        try {
            URLConnection connection = queryURL.openConnection();
            connection.setRequestProperty("Accept", "application/json");
            in = connection.getInputStream();

            String response = IOUtils.toString(in);
            return parseResponse(response);
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

private Result fetchSonarStatus ( URL queryURL ) throws IOException , SonarBreakException { InputStream in = null ; try { URLConnection connection = queryURL . openConnection ( ) ; connection . setRequestProperty ( "Accept" , "application/json" ) ; in = connection . getInputStream ( ) ; String response = IOUtils . toString ( in ) ; return parseResponse ( response ) ; } finally { IOUtils . closeQuietly ( in ) ; } }

Get the status of a build project from sonar.  This returns the current status that sonar has and does not
do any checking to ensure it matches the current project

@param queryURL The sonar URL to hit to get the status
@return The sonar response include quality gate status
@throws IOException
@throws SonarBreakException

Get the status of a build project from sonar . This returns the current status that sonar has and does not do any checking to ensure it matches the current project


protected static Result parseResponse(String response) throws SonarBreakException {
        ObjectMapper mapper = new ObjectMapper();
        final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        mapper.setDateFormat(df);
        List<Result> results;
        try {
            results = mapper.readValue(response, new TypeReference<List<Result>>() {
            });
        } catch (IOException e) {
            throw new SonarBreakException("Unable to parse the json into a List of QualityGateResults.  Json is: " + response, e);
        }
        if (results == null || results.size() != 1) {
            throw new SonarBreakException("Unable to deserialize JSON response: " + response);
        }
        return results.get(0);
    }

Parses the string response from sonar into POJOs.

@param response The json response from the sonar server.
@return Object representing the Sonar response
@throws SonarBreakException Thrown if the response is not JSON or it does not contain quality gate data.

Parses the string response from sonar into POJOs .


@Override
    public RepositoryManagerResult extractBuildArtifacts() throws RepositoryManagerException {
        TrackedContentDTO report;
        try {
            IndyFoloAdminClientModule foloAdmin = indy.module(IndyFoloAdminClientModule.class);
            boolean sealed = foloAdmin.sealTrackingRecord(buildContentId);
            if (!sealed) {
                throw new RepositoryManagerException("Failed to seal content-tracking record for: %s.", buildContentId);
            }

            report = foloAdmin.getTrackingReport(buildContentId);
        } catch (IndyClientException e) {
            throw new RepositoryManagerException("Failed to retrieve tracking report for: %s. Reason: %s", e, buildContentId,
                    e.getMessage());
        }
        if (report == null) {
            throw new RepositoryManagerException("Failed to retrieve tracking report for: %s.", buildContentId);
        }

        Comparator<Artifact> comp = (one, two) -> one.getIdentifier().compareTo(two.getIdentifier());

        List<Artifact> uploads = processUploads(report);
        Collections.sort(uploads, comp);

        List<Artifact> downloads = processDownloads(report);
        Collections.sort(downloads, comp);

        try {
            StoreKey key = new StoreKey(packageType, StoreType.group, buildContentId);
            serviceAccountIndy.stores().delete(key, "[Post-Build] Removing build aggregation group: " + buildContentId);
        } catch (IndyClientException e) {
            throw new RepositoryManagerException("Failed to retrieve Indy stores module. Reason: %s", e, e.getMessage());
        }

        Logger logger = LoggerFactory.getLogger(getClass());
        logger.info("Returning built artifacts / dependencies:\nUploads:\n  {}\n\nDownloads:\n  {}\n\n",
                StringUtils.join(uploads, "\n  "), StringUtils.join(downloads, "\n  "));

        String log = "";
        CompletionStatus status = CompletionStatus.SUCCESS;
        try {
            promoteToBuildContentSet(uploads);
        } catch (RepositoryManagerException rme) {
            status = CompletionStatus.FAILED;
            log = rme.getMessage();
            logger.error("Promotion validation error(s): \n" + log);
            userLog.error("Artifact promotion failed. Promotion validation error(s): {}", log);
            // prevent saving artifacts and dependencies to a failed build
            downloads = Collections.emptyList();
            uploads = Collections.emptyList();
        }

        return new IndyRepositoryManagerResult(uploads, downloads, buildContentId, log, status);
    }

Retrieve tracking report from repository manager. Add each tracked download to the dependencies of the build result. Add
each tracked upload to the built artifacts of the build result. Promote uploaded artifacts to the product-level storage.
Finally, clear the tracking report, and delete the hosted repository + group associated with the completed build.

Retrieve tracking report from repository manager . Add each tracked download to the dependencies of the build result . Add each tracked upload to the built artifacts of the build result . Promote uploaded artifacts to the product - level storage . Finally clear the tracking report and delete the hosted repository + group associated with the completed build .


private List<Artifact> processUploads(TrackedContentDTO report)
            throws RepositoryManagerException {
        Logger logger = LoggerFactory.getLogger(getClass());

        Set<TrackedContentEntryDTO> uploads = report.getUploads();
        if (uploads != null) {
            List<Artifact> builds = new ArrayList<>();

            for (TrackedContentEntryDTO upload : uploads) {
                String path = upload.getPath();
                StoreKey storeKey = upload.getStoreKey();
                if (ignoreContent(storeKey.getPackageType(), path)) {
                    logger.debug("Ignoring upload (matched in ignored-suffixes): {} (From: {})", path, storeKey);
                    continue;
                }

                String identifier = computeIdentifier(upload);

                logger.info("Recording upload: {}", identifier);

                IndyContentClientModule content;
                try {
                    content = indy.content();
                } catch (IndyClientException e) {
                    throw new RepositoryManagerException("Failed to retrieve Indy content module. Reason: %s", e, e.getMessage());
                }

                RepositoryType repoType = toRepoType(storeKey.getPackageType());
                TargetRepository targetRepository = getUploadsTargetRepository(repoType, content);

                ArtifactQuality artifactQuality = getArtifactQuality(isTempBuild);
                Artifact.Builder artifactBuilder = Artifact.Builder.newBuilder()
                        .md5(upload.getMd5())
                        .sha1(upload.getSha1())
                        .sha256(upload.getSha256())
                        .size(upload.getSize())
                        .deployPath(upload.getPath())
                        .filename(new File(path).getName())
                        .identifier(identifier)
                        .targetRepository(targetRepository)
                        .artifactQuality(artifactQuality);

                Artifact artifact = validateArtifact(artifactBuilder.build());
                builds.add(artifact);
            }

            return builds;
        }
        return Collections.emptyList();
    }

Return output artifacts metadata.

@param report The tracking report that contains info about artifacts uploaded (output) from the build
@return List of output artifacts meta data
@throws RepositoryManagerException In case of a client API transport error or an error during promotion of artifacts


private String computeIdentifier(final TrackedContentEntryDTO transfer) {
        String identifier = null;

        switch (transfer.getStoreKey().getPackageType()) {
            case MAVEN_PKG_KEY:
                ArtifactPathInfo pathInfo = ArtifactPathInfo.parse(transfer.getPath());
                if (pathInfo != null) {
                    ArtifactRef aref = new SimpleArtifactRef(pathInfo.getProjectId(), pathInfo.getType(), pathInfo.getClassifier());
                    identifier = aref.toString();
                }
                break;

            case NPM_PKG_KEY:
                NpmPackagePathInfo npmPathInfo = NpmPackagePathInfo.parse(transfer.getPath());
                if (npmPathInfo != null) {
                    NpmPackageRef packageRef = new NpmPackageRef(npmPathInfo.getName(), npmPathInfo.getVersion());
                    identifier = packageRef.toString();
                }
                break;

            case GENERIC_PKG_KEY:
                // handle generic downloads along with other invalid download paths for other package types
                break;

            default:
                // do not do anything by default
                logger.warn("Package type {} is not handled by Indy repository session.", transfer.getStoreKey().getPackageType());
                break;
        }

        if (identifier == null) {
            identifier = computeGenericIdentifier(transfer.getOriginUrl(), transfer.getLocalUrl(), transfer.getSha256());
        }

        return identifier;
    }

Computes identifier string for an artifact. If the download path is valid for a package-type specific artifact it
creates the identifier accordingly.

@param transfer the download or upload that we want to generate identifier for
@return generated identifier

Computes identifier string for an artifact . If the download path is valid for a package - type specific artifact it creates the identifier accordingly .


private String computeGenericIdentifier(String originUrl, String localUrl, String sha256) {
        String identifier = originUrl;
        if (identifier == null) {
            // this is from/to a hosted repository, either the build repo or something like that.
            identifier = localUrl;
        }
        identifier += '|' + sha256;
        return identifier;
    }

Compute the identifier string for a generic download, that does not match package type specific files structure.
It prefers to use the origin URL if it is not empty. In case it is then it uses local URL, which can never be
empty, it is the local file mirror in Indy. After that it attaches the sha256 separated by a pipe.

@param originUrl the origin URL of the transfer, it can be null
@param localUrl url where the artifact was backed up in Indy
@param sha256 the SHA-256 of the transfer
@return the generated identifier

Compute the identifier string for a generic download that does not match package type specific files structure . It prefers to use the origin URL if it is not empty . In case it is then it uses local URL which can never be empty it is the local file mirror in Indy . After that it attaches the sha256 separated by a pipe .


private Artifact validateArtifact(Artifact artifact) throws RepositoryManagerException {
        Set<ConstraintViolation<Artifact>> violations = validator.validate(artifact);
        if (!violations.isEmpty()) {
            throw new RepositoryManagerException("Repository manager returned invalid artifact: " + artifact.toString() + " Constraint Violations: %s", violations);
        }
        return artifact;
    }

Check artifact for any validation errors.  If there are constraint violations, then a RepositoryManagerException is thrown.
Otherwise the artifact is returned.

@param artifact to validate
@return the same artifact
@throws RepositoryManagerException if there are constraint violations

Check artifact for any validation errors . If there are constraint violations then a RepositoryManagerException is thrown . Otherwise the artifact is returned .


public boolean hasConfigDependencyOn(BuildTask buildTask) {
        if (buildTask == null || this.equals(buildTask)) {
            return false;
        }

        BuildConfiguration buildConfiguration = buildConfigurationAudited.getBuildConfiguration();
        if (buildConfiguration == null || buildConfiguration.getAllDependencies() == null) {
            return false;
        }

        return buildConfiguration.dependsOn(buildTask.getBuildConfigurationAudited().getBuildConfiguration());
    }

public boolean hasConfigDependencyOn ( BuildTask buildTask ) { if ( buildTask == null || this . equals ( buildTask ) ) { return false ; } BuildConfiguration buildConfiguration = buildConfigurationAudited . getBuildConfiguration ( ) ; if ( buildConfiguration == null || buildConfiguration . getAllDependencies ( ) == null ) { return false ; } return buildConfiguration . dependsOn ( buildTask . getBuildConfigurationAudited ( ) . getBuildConfiguration ( ) ) ; }

Check if this build task has a build configuration dependency on the given build task.
The search include transitive dependencies.

@param buildTask The buildTask with the config to check
@return true if this task's build config has a dependency (including transitive) on the build config of the given task, otherwise false

Check if this build task has a build configuration dependency on the given build task . The search include transitive dependencies .


public boolean hasDirectConfigDependencyOn(BuildTask buildTask) {
        if (buildTask == null || this.equals(buildTask)) {
            return false;
        }

        BuildConfiguration buildConfiguration = buildConfigurationAudited.getBuildConfiguration();
        if (buildConfiguration == null || buildConfiguration.getDependencies() == null) {
            return false;
        }

        return buildConfiguration.getDependencies().contains(buildTask.getBuildConfigurationAudited().getBuildConfiguration());
    }

public boolean hasDirectConfigDependencyOn ( BuildTask buildTask ) { if ( buildTask == null || this . equals ( buildTask ) ) { return false ; } BuildConfiguration buildConfiguration = buildConfigurationAudited . getBuildConfiguration ( ) ; if ( buildConfiguration == null || buildConfiguration . getDependencies ( ) == null ) { return false ; } return buildConfiguration . getDependencies ( ) . contains ( buildTask . getBuildConfigurationAudited ( ) . getBuildConfiguration ( ) ) ; }

Check if this build task has a direct build configuration dependency on the given build task

@param buildTask The buildTask with the config to check
@return true if this task's build config has a direct dependency on the build config of the given task, otherwise false


public <T extends AbstractModuleConfig> T parseJSONPNCConfig(
            String configContent, ConfigProvider<T> provider) throws ConfigurationParseException {
        try {
            ObjectMapper mapper = new ObjectMapper();
            provider.registerProvider(mapper);

            PNCModuleGroup pncGroup = getModuleGroup(mapper, configContent,
                    PNCModuleGroup.class);

            for (AbstractModuleConfig config : pncGroup.getConfigs()) {
                if (config.getClass().isAssignableFrom(provider.getType())) {
                    return (T) config;
                }
            }
            throw new ConfigurationParseException("Did not find config for provider " + provider.getType().getSimpleName() + ".");
        } catch (IOException | RuntimeException e) {
            log.error(e.getMessage());
            throw new ConfigurationParseException("Config could not be parsed", e);
        }
    }

public
<
T
extends
AbstractModuleConfig
>
T
parseJSONPNCConfig
(
String
configContent
,
ConfigProvider
<
T
>
provider
)
throws
ConfigurationParseException
{
try
{
ObjectMapper
mapper
=
new
ObjectMapper
(
)
;
provider
.
registerProvider
(
mapper
)
;
PNCModuleGroup
pncGroup
=
getModuleGroup
(
mapper
,
configContent
,
PNCModuleGroup
.
class
)
;
for
(
AbstractModuleConfig
config
:
pncGroup
.
getConfigs
(
)
)
{
if
(
config
.
getClass
(
)
.
isAssignableFrom
(
provider
.
getType
(
)
)
)
{
return
(
T
)
config
;
}
}
throw
new
ConfigurationParseException
(
"Did not find config for provider "
+
provider
.
getType
(
)
.
getSimpleName
(
)
+
"."
)
;
}
catch
(
IOException
|
RuntimeException
e
)
{
log
.
error
(
e
.
getMessage
(
)
)
;
throw
new
ConfigurationParseException
(
"Config could not be parsed"
,
e
)
;
}
}

Loads JSON configuration to the module configuration object

@param <T> module config
@param configContent Configuration in JSON
@param provider configuration provider of given module config type
@return Loaded configuration
@throws ConfigurationParseException Thrown if configuration string is malformed


@Override
    public void monitor(Consumer<CompletedRepositoryDeletion> onComplete, Consumer<Exception> onError) {
        try {
            StoreKey fromKey = new StoreKey(pakageType, fromType, fromId);
            if (indy.stores().exists(fromKey)) {
                indy.stores().delete(fromKey, "Deleting artifacts for PNC build");
            }

            onComplete.accept(new IndyCompletedDeletion(true));

        } catch (IndyClientException e) {
            onError.accept(e);
        }
    }

@
Override
public
void
monitor
(
Consumer
<
CompletedRepositoryDeletion
>
onComplete
,
Consumer
<
Exception
>
onError
)
{
try
{
StoreKey
fromKey
=
new
StoreKey
(
pakageType
,
fromType
,
fromId
)
;
if
(
indy
.
stores
(
)
.
exists
(
fromKey
)
)
{
indy
.
stores
(
)
.
delete
(
fromKey
,
"Deleting artifacts for PNC build"
)
;
}
onComplete
.
accept
(
new
IndyCompletedDeletion
(
true
)
)
;
}
catch
(
IndyClientException
e
)
{
onError
.
accept
(
e
)
;
}
}

Trigger the repository deletion configured for this instance, and send the result to the appropriate consumer.

@param onComplete The consumer which will handle non-error results
@param onError Handles errors

Trigger the repository deletion configured for this instance and send the result to the appropriate consumer .


public void taskStatusUpdatedToFinalState() {
        // If any of the build tasks have failed or all are complete, then the build set is done
        if(buildTasks.stream().anyMatch(bt -> bt.getStatus().equals(BuildCoordinationStatus.CANCELLED))) {
            log.debug("Marking build set as CANCELLED as one or more tasks were cancelled. BuildSetTask: {}", this);
            if (log.isDebugEnabled()) {
                logTasksStatus(buildTasks);
            }
            buildConfigSetRecord.ifPresent(r -> r.setStatus(BuildStatus.CANCELLED));
            finishBuildSetTask();
        } else if(buildTasks.stream().anyMatch(bt -> bt.getStatus().hasFailed())) {
            log.debug("Marking build set as FAILED as one or more tasks failed. BuildSetTask: {}", this);
            if (log.isDebugEnabled()) {
                logTasksStatus(buildTasks);
            }
            buildConfigSetRecord.ifPresent(r -> r.setStatus(BuildStatus.FAILED));
            finishBuildSetTask();
        } else if (buildTasks.stream().allMatch(bt -> bt.getStatus().isCompleted())) {
            log.debug("Marking build set as SUCCESS. BuildSetTask: {}", this);
            buildConfigSetRecord.ifPresent(r -> r.setStatus(BuildStatus.SUCCESS));
            finishBuildSetTask();
        } else {
            if (log.isTraceEnabled()) {
                List<Integer> running = buildTasks.stream()
                        .filter(bt -> !bt.getStatus().isCompleted())
                        .filter(bt -> !bt.getStatus().hasFailed())
                        .map(BuildTask::getId)
                        .collect(Collectors.toList());
                log.trace("There are still running or waiting builds [{}].", running);
            }
        }
    }

Notify the set that the state of one of it's tasks has changed.

Notify the set that the state of one of it s tasks has changed .


public BuildTask getBuildTask(BuildConfigurationAudited buildConfigurationAudited) {
        return buildTasks.stream().filter((bt) -> bt.getBuildConfigurationAudited().equals(buildConfigurationAudited)).findFirst().orElse(null);
    }

public BuildTask getBuildTask ( BuildConfigurationAudited buildConfigurationAudited ) { return buildTasks . stream ( ) . filter ( ( bt ) - > bt . getBuildConfigurationAudited ( ) . equals ( buildConfigurationAudited ) ) . findFirst ( ) . orElse ( null ) ; }

Get the build task which contains the given audited build configuration

@param buildConfigurationAudited A BuildConfigurationAudited entity
@return The build task with the matching configuration, or null if there is none


@Override
    public void monitor(Consumer<CompletedRepositoryPromotion> onComplete, Consumer<Exception> onError) {
        try {
            StoreKey fromKey = new StoreKey(pakageType, fromType, fromId);
            if (!indy.stores().exists(fromKey)) {
                throw new RepositoryManagerException("No such %s repository: %s", fromType.singularEndpointName(), fromId);
            }

            StoreKey toKey = new StoreKey(pakageType, StoreType.group, toId);
            Group recordSetGroup = indy.stores().load(toKey, Group.class);
            if (recordSetGroup == null) {
                throw new RepositoryManagerException("No such group: %s", toId);
            }

            recordSetGroup.addConstituent(fromKey);

            boolean result = indy.stores().update(recordSetGroup,
                    "Promoting " + fromType.singularEndpointName() + " repository : " + fromId + " to group: " + toId);

            onComplete.accept(new IndyCompletedPromotion(result));

        } catch (IndyClientException | RepositoryManagerException e) {
            onError.accept(e);
        }
    }

@
Override
public
void
monitor
(
Consumer
<
CompletedRepositoryPromotion
>
onComplete
,
Consumer
<
Exception
>
onError
)
{
try
{
StoreKey
fromKey
=
new
StoreKey
(
pakageType
,
fromType
,
fromId
)
;
if
(
!
indy
.
stores
(
)
.
exists
(
fromKey
)
)
{
throw
new
RepositoryManagerException
(
"No such %s repository: %s"
,
fromType
.
singularEndpointName
(
)
,
fromId
)
;
}
StoreKey
toKey
=
new
StoreKey
(
pakageType
,
StoreType
.
group
,
toId
)
;
Group
recordSetGroup
=
indy
.
stores
(
)
.
load
(
toKey
,
Group
.
class
)
;
if
(
recordSetGroup
==
)
{
throw
new
RepositoryManagerException
(
"No such group: %s"
,
toId
)
;
}
recordSetGroup
.
addConstituent
(
fromKey
)
;
boolean
result
=
indy
.
stores
(
)
.
update
(
recordSetGroup
,
"Promoting "
+
fromType
.
singularEndpointName
(
)
+
" repository : "
+
fromId
+
" to group: "
+
toId
)
;
onComplete
.
accept
(
new
IndyCompletedPromotion
(
result
)
)
;
}
catch
(
IndyClientException
|
RepositoryManagerException
e
)
{
onError
.
accept
(
e
)
;
}
}

Trigger the repository promotion configured for this instance, and send the result to the appropriate consumer.

@param onComplete The consumer which will handle non-error results
@param onError Handles errors

Trigger the repository promotion configured for this instance and send the result to the appropriate consumer .


public static <T> void merge(Graph<T> target, Graph<T> toMerge) {
        for (Vertex<T> vertex : toMerge.getVerticies()) {
            target.addVertex(vertex);
        }

        // merge edges
        List<Edge<T>> edges = target.getEdges();
        for (Edge newEdge : toMerge.getEdges()) {
            Optional<Edge<T>> any = edges.stream()
                    .filter(existing ->
                            existing.getFrom().getName().equals(newEdge.getFrom().getName())
                             && existing.getTo().getName().equals(newEdge.getTo().getName())
                    ).findAny();
            if (!any.isPresent()) {
                edges.add(newEdge);
            }
        }
    }

public
static
<
T
>
void
merge
(
Graph
<
T
>
target
,
Graph
<
T
>
toMerge
)
{
for
(
Vertex
<
T
>
vertex
:
toMerge
.
getVerticies
(
)
)
{
target
.
addVertex
(
vertex
)
;
}
// merge edges
List
<
Edge
<
T
>
>
edges
=
target
.
getEdges
(
)
;
for
(
Edge
newEdge
:
toMerge
.
getEdges
(
)
)
{
Optional
<
Edge
<
T
>>
any
=
edges
.
stream
(
)
.
filter
(
existing
->
existing
.
getFrom
(
)
.
getName
(
)
.
equals
(
newEdge
.
getFrom
(
)
.
getName
(
)
)
&&
existing
.
getTo
(
)
.
getName
(
)
.
equals
(
newEdge
.
getTo
(
)
.
getName
(
)
)
)
.
findAny
(
)
;
if
(
!
any
.
isPresent
(
)
)
{
edges
.
add
(
newEdge
)
;
}
}
}

Adds all elements from toMerge to target.

Adds all elements from toMerge to target .


public static String readFileAsString(File fileName) throws IOException {
        try (Scanner sc = new Scanner(fileName, Charset.defaultCharset().name())) {
            sc.useDelimiter("\\A");
            return sc.next();
        }
    }

public static String readFileAsString ( File fileName ) throws IOException { try ( Scanner sc = new Scanner ( fileName , Charset . defaultCharset ( ) . name ( ) ) ) { sc . useDelimiter ( "\\A" ) ; return sc . next ( ) ; } }

Reads whole content of file to String

@param fileName Existing file
@return File content
@throws IOException Thrown if data couldn't be loaded


public static String readStreamAsString(InputStream stream) throws IOException {
        try (Scanner sc = new Scanner(stream, Charset.defaultCharset().name())) {
            sc.useDelimiter("\\A");
            return sc.next();
        }
    }

public static String readStreamAsString ( InputStream stream ) throws IOException { try ( Scanner sc = new Scanner ( stream , Charset . defaultCharset ( ) . name ( ) ) ) { sc . useDelimiter ( "\\A" ) ; return sc . next ( ) ; } }

Reads whole content of input stream to String

@param stream Opened stream
@return Stream content
@throws IOException Thrown if data couldn't be loaded


public void startRelease(ProductMilestone milestone, String accessToken) {
        ProductMilestoneRelease release = triggerRelease(milestone, accessToken);
        productMilestoneReleaseRepository.save(release);
    }

public void startRelease ( ProductMilestone milestone , String accessToken ) { ProductMilestoneRelease release = triggerRelease ( milestone , accessToken ) ; productMilestoneReleaseRepository . save ( release ) ; }

Starts milestone release process

@param milestone product milestone to start the release for
@param accessToken


public void cleanup() { //TODO remove tasks immediately after the completion, see: BuildTaskEndpoint.buildTaskCompleted
        log.debug("Bpm manager tasks cleanup started");

        if (session == null) {
            log.error("Kie session not available.");
        }

        Map<Integer, BpmTask> clonedTaskMap = new HashMap<>(this.tasks);

        Set<Integer> toBeRemoved = clonedTaskMap.values().stream()
                .filter(bpmTask -> {
                    if (bpmTask == null) {
                        log.warn("Listing invalid entry for removal from the tasks list.");
                        return true;
                    }
                    log.debug("Attempting to fetch process instance for bpmTask: {}.", bpmTask.getTaskId());
                    Long processInstanceId = bpmTask.getProcessInstanceId();
                    ProcessInstance processInstance = session.getProcessInstance(processInstanceId);
                    log.debug("fetched: {}", processInstance);
                    if (processInstance == null) // instance has been terminated from outside
                        return true;
                    int state = processInstance.getState();
                    return state == STATE_COMPLETED || state == STATE_ABORTED;
                })
                .map(BpmTask::getTaskId)
                .collect(Collectors.toSet());
        toBeRemoved.forEach(id -> {
            BpmTask removed = tasks.remove(id);
            if (removed != null) {
                log.debug("Removed bpmTask.id: {}.", removed.getTaskId());
            } else {
                log.warn("Unable to remove bpmTask.id: {}.", id);
            }
        });

        log.debug("Bpm manager tasks cleanup finished");
    }

Regularly cleans finished BPM tasks asynchronously
Immediate cleanup is not usable because of NCL-2300

Regularly cleans finished BPM tasks asynchronously Immediate cleanup is not usable because of NCL - 2300


@Deprecated
    public Integer getTaskIdByBuildId(int buildId) {
        List<Integer> result = tasks.values().stream()
                .filter(t -> t instanceof BpmBuildTask)
                .filter(t -> ((BpmBuildTask) t).getBuildTask().getId() == buildId)
                .map(BpmTask::getTaskId)
                .collect(Collectors.toList());
        if (result.size() > 1)
            throw new IllegalStateException("More that one task with the same build id: " + result);
        return result.size() == 1 ? result.get(0) : null;
    }

This method solves backwards compatibility problem.
It will be removed soon.

This method solves backwards compatibility problem . It will be removed soon .


public static <T> Collector<Collection<T>, List<T>, List<T>> toFlatList() {
        return Collector.of(
                ArrayList::new,
                List::addAll,
                (left, right) -> {
                    left.addAll(right);
                    return left;
                });
    }

public static < T > Collector < Collection < T > , List < T > , List < T > > toFlatList ( ) { return Collector . of ( ArrayList :: new , List :: addAll , ( left , right ) -> { left . addAll ( right ) ; return left ; } ) ; }

Flattening collector.
Look at StreamCollectorsTest for example usage

@param <T> type of elements in the collections
@return flattened list of elements from all of the collections

Flattening collector . Look at StreamCollectorsTest for example usage


@Schedule
    public void cleanupExpiredTemporaryBuilds() throws ValidationException {
        log.info("Regular cleanup of expired temporary builds started. Removing builds older than " + TEMPORARY_BUILD_LIFESPAN
                + " days.");

        Date expirationThreshold = TimeUtils.getDateXDaysAgo(TEMPORARY_BUILD_LIFESPAN);

        String authToken = serviceClient.getAuthToken();
        deleteExpiredBuildConfigSetRecords(expirationThreshold, authToken);
        deleteExpiredBuildRecords(expirationThreshold, authToken);

        log.info("Regular cleanup of expired temporary builds finished.");
    }

Cleanup old temporary builds every midnight


private void setupBuildRepos(BuildExecution execution, String packageType, Indy indy, Map<String, String> genericParameters) throws IndyClientException {

        String buildContentId = execution.getBuildContentId();
        int id = execution.getId();

        // if the build-level group doesn't exist, create it.
        StoreKey groupKey = new StoreKey(packageType, StoreType.group, buildContentId);

        if (!indy.stores().exists(groupKey)) {
            // if the product-level storage repo (for in-progress product builds) doesn't exist, create it.
            StoreKey hostedKey = new StoreKey(packageType, StoreType.hosted, buildContentId);
            boolean tempBuild = execution.isTempBuild();
            if (!indy.stores().exists(hostedKey)) {
                HostedRepository buildArtifacts = new HostedRepository(packageType, buildContentId);
                buildArtifacts.setAllowSnapshots(tempBuild);
                buildArtifacts.setAllowReleases(true);

                buildArtifacts.setDescription(String.format("Build output for PNC %s build #%s", packageType, id));

                indy.stores().create(buildArtifacts, "Creating hosted repository for " + packageType + " build: " + id
                        + " (repo: " + buildContentId + ")", HostedRepository.class);
            }

            Group buildGroup = new Group(packageType, buildContentId);
            String adjective = tempBuild ? "temporary " : "";
            buildGroup.setDescription(String.format("Aggregation group for PNC %sbuild #%s", adjective, id));

            // build-local artifacts
            buildGroup.addConstituent(hostedKey);

            // Global-level repos, for captured/shared artifacts and access to the outside world
            addGlobalConstituents(packageType, buildGroup, tempBuild);

            // add extra repositories removed from poms by the adjust process and set in BC by user
            List<ArtifactRepository> extraDependencyRepositories = extractExtraRepositoriesFromGenericParameters(genericParameters);
            if (execution.getArtifactRepositories() != null) {
                extraDependencyRepositories.addAll(execution.getArtifactRepositories());
            }
            addExtraConstituents(packageType, extraDependencyRepositories, id, buildContentId, indy, buildGroup);

            indy.stores().create(buildGroup, "Creating repository group for resolving artifacts in build: " + id
                    + " (repo: " + buildContentId + ")", Group.class);
        }
    }

Create the hosted repository and group necessary to support a single build. The hosted repository holds artifacts
uploaded from the build, and the group coordinates access to this hosted repository, along with content from the
product-level content group with which this build is associated. The group also provides a tracking target, so the
repository manager can keep track of downloads and uploads for the build.

@param execution The execution object, which contains the content id for creating the repo, and the build id.
@param packageType the package type key used by Indy
@throws IndyClientException

Create the hosted repository and group necessary to support a single build . The hosted repository holds artifacts uploaded from the build and the group coordinates access to this hosted repository along with content from the product - level content group with which this build is associated . The group also provides a tracking target so the repository manager can keep track of downloads and uploads for the build .


private void onRCCreationSuccess(BpmNotificationRest notification, BuildConfigurationRest buildConfigurationRest) {
        LOG.debug("Received BPM event RC_CREATION_SUCCESS: " + notification);

        BpmStringMapNotificationRest repositoryCreationTaskResult = (BpmStringMapNotificationRest) notification;

        int repositoryConfigurationId = -1;
        int buildConfigurationSavedId = -1;
        try {
            repositoryConfigurationId = Integer.valueOf(repositoryCreationTaskResult.getData().get("repositoryConfigurationId"));
        } catch (NumberFormatException ex) {
            String errorMessage = "Receive notification about successful BC creation '" + repositoryCreationTaskResult
                    + "' but the ID of the newly created RC '" + repositoryCreationTaskResult.getData()
                    .get("repositoryConfigurationId")
                    + "' is not a number. It should be present under 'repositoryConfigurationId' key.";

            LOG.error(errorMessage, ex);
            sendErrorMessage(repositoryConfigurationId, buildConfigurationSavedId, errorMessage);
            return;
        }

        RepositoryConfiguration repositoryConfiguration = repositoryConfigurationRepository.queryById(repositoryConfigurationId);
        if (repositoryConfiguration == null) {
            String errorMessage = "Repository Configuration was not found in database.";
            LOG.error(errorMessage);
            sendErrorMessage(repositoryConfigurationId, buildConfigurationSavedId, errorMessage);
            return;
        }

        if (buildConfigurationRest != null) { //TODO test me
            BuildConfiguration buildConfiguration = buildConfigurationRest.toDBEntityBuilder()
                    .repositoryConfiguration(repositoryConfiguration)
                    .build();
            BuildConfiguration buildConfigurationSaved = buildConfigurationRepository.save(buildConfiguration);
            buildConfigurationSavedId = buildConfigurationSaved.getId();

            Set<Integer> bcSetIds = buildConfigurationRest.getBuildConfigurationSetIds();
            try {
                if (bcSetIds != null) {
                    addBuildConfigurationToSet(buildConfigurationSaved, bcSetIds);
                }
            } catch (Exception e) {
                LOG.error(e.getMessage());
                sendErrorMessage(repositoryConfigurationId, buildConfigurationSavedId, e.getMessage());
                return;
            }
        }

        RepositoryCreationResultRest repositoryCreationResultRest
                = new RepositoryCreationResultRest(
                        repositoryConfigurationId,
                        buildConfigurationSavedId,
                        RepositoryCreationResultRest.EventType.RC_CREATION_SUCCESS,
                        null);

        wsNotifier.sendMessage(repositoryCreationResultRest); //TODO test me!
    }

Given the successful BC creation, add the BC into the BC sets. This solution has been
selected because if this was done in BPM process there would have to be a foreach cycle and
at least two REST requests for each BC Set ID. The process would become too complicated.
Notification listeners are ideal for these kind of operations.

Given the successful BC creation add the BC into the BC sets . This solution has been selected because if this was done in BPM process there would have to be a foreach cycle and at least two REST requests for each BC Set ID . The process would become too complicated . Notification listeners are ideal for these kind of operations .


private void addWebsocketForwardingListeners(RepositoryCreationTask task) {
        Consumer<? extends BpmNotificationRest> doNotify = (e) -> wsNotifier.sendMessage(e);
        task.addListener(BpmEventType.RC_REPO_CREATION_SUCCESS, doNotify);
        task.addListener(BpmEventType.RC_REPO_CREATION_ERROR, doNotify);
        task.addListener(BpmEventType.RC_REPO_CLONE_SUCCESS, doNotify);
        task.addListener(BpmEventType.RC_REPO_CLONE_ERROR, doNotify);
        //clients are notified from callback in startRCreationTask
        //task.addListener(BpmEventType.RC_CREATION_SUCCESS, doNotify);
        task.addListener(BpmEventType.RC_CREATION_ERROR, doNotify);
    }

This method will add listeners to all important RCC event types
and forward the event to WS clients.

This method will add listeners to all important RCC event types and forward the event to WS clients .


public static Artifact mockImportedArtifact(int id) {
        return getArtifactBuilder(id)
                .importDate(Date.from(Instant.now()))
                .originUrl("http://central.maven.org/org/jboss/mock/artifactFile" + id + ".jar")
                .build();
    }

Create an artifact with an import date and origin url


public static void setSslRequired(boolean sslRequired) {
        if (HttpUtil.sslRequired != sslRequired) {
            HttpUtil.sslRequired = sslRequired;
            HttpUtil.httpClient = null;
        }
    }

public static void setSslRequired ( boolean sslRequired ) { if ( HttpUtil . sslRequired != sslRequired ) { HttpUtil . sslRequired = sslRequired ; HttpUtil . httpClient = null ; } }

Sets flag telling if SSL hostname validation should be done which also clears the cached httpClient. This method
is not thread-safe and could cause race conditions if the class is used with different settings at the same
time, but that is not expected.

@param sslRequired the desired value

Sets flag telling if SSL hostname validation should be done which also clears the cached httpClient . This method is not thread - safe and could cause race conditions if the class is used with different settings at the same time but that is not expected .


public Result deleteTemporaryBuild(Integer buildRecordId, String authToken) throws ValidationException {
        BuildRecord buildRecord = buildRecordRepository.findByIdFetchAllProperties(buildRecordId);
        if (!buildRecord.isTemporaryBuild()) {
            throw new ValidationException("Only deletion of the temporary builds is allowed");
        }
        log.info("Starting deletion of a temporary build " + buildRecord + "; Built artifacts: " + buildRecord.getBuiltArtifacts()
                + "; Dependencies: " + buildRecord.getDependencies());

        Result result = remoteBuildsCleaner.deleteRemoteBuilds(buildRecord, authToken);
        if (!result.isSuccess()) {
            log.error("Failed to delete remote temporary builds for BR.id:{}.", buildRecord.getId());
            return new Result(buildRecordId.toString(), Result.Status.FAILED, "Failed to delete remote temporary builds.");
        }

        /** Delete relation between BuildRecord and Artifact */
        Set<Artifact> artifactsToBeDeleted = new HashSet<>();

        removeRelationBuildRecordArtifact(buildRecord, artifactsToBeDeleted);

        /**
         * Delete artifacts, if the artifacts are not used in other builds
         */
        deleteArtifacts(artifactsToBeDeleted);

        deleteDependencies(buildRecord);

        buildRecordRepository.delete(buildRecord.getId());
        log.info("Deletion of the temporary build {} finished successfully.", buildRecord);
        return new Result(buildRecordId.toString(), Result.Status.SUCCESS);
    }

Deletes a temporary build and artifacts created during the build or orphan dependencies used

@param buildRecordId BuildRecord to be deleted
@param authToken
@return true if success


public Result deleteTemporaryBuildConfigSetRecord(Integer buildConfigSetRecordId, String authToken)
            throws ValidationException {

        BuildConfigSetRecord buildConfigSetRecord = buildConfigSetRecordRepository.queryById(buildConfigSetRecordId);
        if (!buildConfigSetRecord.isTemporaryBuild()) {
            throw new ValidationException("Only deletion of the temporary builds is allowed");
        }
        log.info("Starting deletion of a temporary build record set " + buildConfigSetRecord);

        for (BuildRecord br : buildConfigSetRecord.getBuildRecords()) {
            Result result = deleteTemporaryBuild(br.getId(), authToken);
            if (!result.isSuccess()) {
                return result;
            }
        }
        buildConfigSetRecordRepository.delete(buildConfigSetRecord.getId());

        log.info("Deletion of a temporary build record set {} finished successfully.", buildConfigSetRecord);
        return new Result(buildConfigSetRecordId.toString(), Result.Status.SUCCESS);
    }

Deletes a BuildConfigSetRecord and BuildRecords produced in the build
@param buildConfigSetRecordId BuildConfigSetRecord to be deleted
@param authToken


@Override
    public BuildSetTask build(BuildConfigurationAudited buildConfigurationAudited,
                              User user,
                              BuildOptions buildOptions) throws BuildConflictException {
        return build0(user, buildOptions, buildConfigurationAudited);
    }

@ Override public BuildSetTask build ( BuildConfigurationAudited buildConfigurationAudited , User user , BuildOptions buildOptions ) throws BuildConflictException { return build0 ( user , buildOptions , buildConfigurationAudited ) ; }

Run a single build.  Uses the settings from the specific revision of a BuildConfiguration.
The dependencies are resolved by the BuildConfiguration relations and are used in the latest revisions

@param buildConfigurationAudited A revision of a BuildConfiguration which will be used.
@param user The user who triggered the build.
@param buildOptions Customization of a build specified by user

@return The new build task
@throws BuildConflictException If there is already a build running with the same build configuration Id and revision

Run a single build . Uses the settings from the specific revision of a BuildConfiguration . The dependencies are resolved by the BuildConfiguration relations and are used in the latest revisions


private void checkForEmptyBuildSetTask(BuildSetTask buildSetTask) {
        if (buildSetTask.getBuildTasks() == null || buildSetTask.getBuildTasks().isEmpty()) {
            updateBuildSetTaskStatus(buildSetTask, BuildSetStatus.REJECTED, "Build config set is empty");
        }
    }

private
void
checkForEmptyBuildSetTask
(
BuildSetTask
buildSetTask
)
{
if
(
buildSetTask
.
getBuildTasks
(
)
==
||
buildSetTask
.
getBuildTasks
(
)
.
isEmpty
(
)
)
{
updateBuildSetTaskStatus
(
buildSetTask
,
BuildSetStatus
.
REJECTED
,
"Build config set is empty"
)
;
}
}

Check if the given build set task is empty and update the status message appropriately


public EnvironmentDriver getDriver(SystemImageType systemImageType) throws ExecutorException {
        for (EnvironmentDriver driver : availableDrivers) {
            if (driver.canRunImageType(systemImageType))
                return driver;
        }

        throw new ExecutorException("No environment driver available for " + systemImageType + " system image type.");
    }

public
EnvironmentDriver
getDriver
(
SystemImageType
systemImageType
)
throws
ExecutorException
{
for
(
EnvironmentDriver
driver
:
availableDrivers
)
{
if
(
driver
.
canRunImageType
(
systemImageType
)
)
return
driver
;
}
throw
new
ExecutorException
(
"No environment driver available for "
+
systemImageType
+
" system image type."
)
;
}

Gets environment driver, which can manage requested environment
@return Available driver for given systemImageType
@throws ExecutorException Throw if no suitable driver for selected environment was found

Gets environment driver which can manage requested environment


public static Predicate<BuildConfiguration> isNotArchived() {
        return (root, query, cb) -> cb.isTrue(root.get(BuildConfiguration_.active));
    }

public static Predicate < BuildConfiguration > isNotArchived ( ) { return ( root , query , cb ) -> cb . isTrue ( root . get ( BuildConfiguration_ . active ) ) ; }

Return a predicate which excludes all archived build configurations
@return


private void loadBuildConfigurations(BuildConfigurationAudited buildConfigAudited) {
        Project project = buildConfigAudited.getProject();
        project.getBuildConfigurations().forEach(BuildConfiguration::getId);
    }

private void loadBuildConfigurations ( BuildConfigurationAudited buildConfigAudited ) { Project project = buildConfigAudited . getProject ( ) ; project . getBuildConfigurations ( ) . forEach ( BuildConfiguration :: getId ) ; }

Fetch build configurations of project to be able access it outside transaction
@param buildConfigAudited build config for which the build configurations are to be fetched


public BuildRecord storeResult(BuildTask buildTask, Optional<BuildResult> buildResult, Throwable e) throws DatastoreException {
        BuildRecord.Builder buildRecordBuilder = initBuildRecordBuilder(buildTask);
        buildRecordBuilder.status(SYSTEM_ERROR);

        StringBuilder errorLog = new StringBuilder();

        buildResult.ifPresent(result -> {

            result.getRepourResult().ifPresent(repourResult -> {
                buildRecordBuilder.executionRootName(repourResult.getExecutionRootName());
                buildRecordBuilder.executionRootVersion(repourResult.getExecutionRootVersion());
                buildRecordBuilder.repourLog(repourResult.getLog());
            });

            result.getBuildDriverResult().ifPresent(
                buildDriverResult -> {
                    errorLog.append(buildDriverResult.getBuildLog());
                    errorLog.append("\n---- End Build Log ----\n");
            });

            result.getRepositoryManagerResult().ifPresent(
                rmr -> {
                    errorLog.append(rmr.getLog());
                    errorLog.append("\n---- End Repository Manager Log ----\n");
            });

            result.getEnvironmentDriverResult().ifPresent(
                r -> {
                    if (r.getLog() != null && !r.getLog().equals(""))
                    errorLog.append(r.getLog());
                    errorLog.append("\n---- End Environment Driver Log ----\n");
            });
        });

        errorLog.append("Build status: ").append(getBuildStatus(buildResult)).append("\n");
        errorLog.append("Caught exception: ").append(e.toString()).append("\n");
        StringWriter stackTraceWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stackTraceWriter));
        errorLog.append(stackTraceWriter.getBuffer());
        buildRecordBuilder.buildLog(errorLog.toString());

        userLog.error("Build status: {}.", getBuildStatus(buildResult));
        log.debug("Storing ERROR result of buildTask.getBuildConfigurationAudited().getName() to datastore.",  e);
        return datastore.storeCompletedBuild(buildRecordBuilder);
    }

Store build result along with error information appended to the build log

@param buildTask task
@param buildResult result of running the task
@param e The error that occurred during the build process
@throws DatastoreException on failure to store data


private BuildRecord.Builder initBuildRecordBuilder(BuildTask buildTask) {
        BuildOptions buildOptions = buildTask.getBuildOptions();
        BuildRecord.Builder builder = BuildRecord.Builder.newBuilder()
                .id(buildTask.getId())
                .buildConfigurationAudited(buildTask.getBuildConfigurationAudited())
                .user(buildTask.getUser())
                .submitTime(buildTask.getSubmitTime())
                .startTime(buildTask.getStartTime())
                .productMilestone(buildTask.getProductMilestone())
                .temporaryBuild(buildOptions.isTemporaryBuild());

        if (buildTask.getEndTime() == null) {
            buildTask.setEndTime(Date.from(Instant.now()));
        }

        builder.endTime(buildTask.getEndTime());

        if (buildTask.getBuildConfigSetRecordId() != null) {
            BuildConfigSetRecord buildConfigSetRecord = datastore.getBuildConfigSetRecordById(buildTask.getBuildConfigSetRecordId());
            builder.buildConfigSetRecord(buildConfigSetRecord);
        }

        List<Integer> dependencies = buildTask.getDependencies().stream().map(t -> t.getId()).collect(Collectors.toList());
        builder.dependencyBuildRecordIds(dependencies.toArray(new Integer[dependencies.size()]));

        List<Integer> dependants = buildTask.getDependants().stream().map(t -> t.getId()).collect(Collectors.toList());
        builder.dependentBuildRecordIds(dependants.toArray(new Integer[dependants.size()]));

        return builder;
    }

private BuildRecord . Builder initBuildRecordBuilder ( BuildTask buildTask ) { BuildOptions buildOptions = buildTask . getBuildOptions ( ) ; BuildRecord . Builder builder = BuildRecord . Builder . newBuilder ( ) . id ( buildTask . getId ( ) ) . buildConfigurationAudited ( buildTask . getBuildConfigurationAudited ( ) ) . user ( buildTask . getUser ( ) ) . submitTime ( buildTask . getSubmitTime ( ) ) . startTime ( buildTask . getStartTime ( ) ) . productMilestone ( buildTask . getProductMilestone ( ) ) . temporaryBuild ( buildOptions . isTemporaryBuild ( ) ) ; if ( buildTask . getEndTime ( ) == null ) { buildTask . setEndTime ( Date . from ( Instant . now ( ) ) ) ; } builder . endTime ( buildTask . getEndTime ( ) ) ; if ( buildTask . getBuildConfigSetRecordId ( ) != null ) { BuildConfigSetRecord buildConfigSetRecord = datastore . getBuildConfigSetRecordById ( buildTask . getBuildConfigSetRecordId ( ) ) ; builder . buildConfigSetRecord ( buildConfigSetRecord ) ; } List < Integer > dependencies = buildTask . getDependencies ( ) . stream ( ) . map ( t -> t . getId ( ) ) . collect ( Collectors . toList ( ) ) ; builder . dependencyBuildRecordIds ( dependencies . toArray ( new Integer [ dependencies . size ( ) ] ) ) ; List < Integer > dependants = buildTask . getDependants ( ) . stream ( ) . map ( t -> t . getId ( ) ) . collect ( Collectors . toList ( ) ) ; builder . dependentBuildRecordIds ( dependants . toArray ( new Integer [ dependants . size ( ) ] ) ) ; return builder ; }

Initialize a new BuildRecord.Builder based on the data contained in the BuildTask.
Note, this must be done inside a transaction because it fetches the BuildRecordSet entities from
the database.

@return The initialized build record builder

Initialize a new BuildRecord . Builder based on the data contained in the BuildTask . Note this must be done inside a transaction because it fetches the BuildRecordSet entities from the database .


public static Predicate<ProductVersion> withBuildConfigurationId(Integer buildConfigurationId) {
        return (root, query, cb) -> {
            SetJoin<ProductVersion, BuildConfiguration> buildConfigurationJoin = root.join(ProductVersion_.buildConfigurations);
            return cb.equal(buildConfigurationJoin.get(BuildConfiguration_.id), buildConfigurationId);
        };
    }

public static Predicate < ProductVersion > withBuildConfigurationId ( Integer buildConfigurationId ) { return ( root , query , cb ) -> { SetJoin < ProductVersion , BuildConfiguration > buildConfigurationJoin = root . join ( ProductVersion_ . buildConfigurations ) ; return cb . equal ( buildConfigurationJoin . get ( BuildConfiguration_ . id ) , buildConfigurationId ) ; } ; }

This predicate returns all the ProductVersions linked to a specified BuildConfiguration