Skip to content

Commit 742dea2

Browse files
committed
Merge branch 'master' into jakarta-wip
2 parents a04d7cf + 1f0017b commit 742dea2

35 files changed

Lines changed: 320 additions & 154 deletions

File tree

.github/workflows/maven-test.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ jobs:
77
build:
88

99
runs-on: ubuntu-latest
10+
env:
11+
TZ: "Europe/London"
1012

1113
steps:
1214
- uses: actions/checkout@v2
@@ -20,7 +22,7 @@ jobs:
2022
java-version: 21
2123
distribution: zulu
2224
# Step that does that actual cache save and restore
23-
- uses: actions/cache@v1
25+
- uses: actions/cache@v4.2.2
2426
with:
2527
path: ~/.m2/repository
2628
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
@@ -30,4 +32,4 @@ jobs:
3032
run: mvn -T3 -B test --file pom.xml
3133
- name: Publish Test Report
3234
if: ${{ always() }}
33-
uses: scacap/action-surefire-report@v1
35+
uses: scacap/action-surefire-report@1a128e49c0585bc0b8e38e541ac3b6e35a5bc727

Makefile

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,8 @@ else
1414
MVN=mvn -T$(MAVEN_PARALLELISM)
1515
endif
1616

17-
ifeq ($(env), azure)
18-
MVN=mvn -T$(MAVEN_PARALLELISM) -P azure
19-
endif
20-
2117
RSYNC=rsync --progress -vzr
2218

23-
ifeq ($(env), azure)
24-
HOST=$(host)
25-
DESTINATION=/opt/tomcat/
26-
WEBAPPS=$(HOST):$(DESTINATION)core-services/webapps
27-
RSYNC=rsync --progress -vzr --chmod=a+wrx --perms
28-
endif
29-
3019
all: install
3120

3221
uman: clean

guice/common/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<parent>
1313
<groupId>com.peterphi.std.guice</groupId>
1414
<artifactId>stdlib-guice-parent</artifactId>
15-
<version>14.7.13-SNAPSHOT</version>
15+
<version>14.7.15-SNAPSHOT</version>
1616
</parent>
1717

1818
<dependencies>

guice/common/src/main/java/com/peterphi/std/guice/restclient/jaxb/webquery/WebQueryParser.java

Lines changed: 86 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ public class WebQueryParser
1818
private static final String WHERE = "WHERE";
1919

2020
private static final String OPEN_BRACKET = "(";
21+
private static final char OPEN_BRACKET_C = '(';
2122
private static final String CLOSE_BRACKET = ")";
23+
private static final char CLOSE_BRACKET_C = ')';
2224
private static final String COMMA = ",";
25+
private static final char COMMA_C = ',';
26+
27+
private static final char COLON_C = ':';
2328

2429
private static final String AND = "AND";
2530
private static final String OR = "OR";
@@ -36,6 +41,9 @@ public class WebQueryParser
3641
private static final String STARTS = "STARTS";
3742
private static final String CONTAINS = "CONTAINS";
3843
private static final String CONTAINS2 = "~=";
44+
45+
// operator token is a run of any of the following:
46+
private static final char[] OPERATORS = new char[]{'=', '<', '>', '~', '!'};
3947

4048
public static WebQuery parse(String search, WebQuery query)
4149
{
@@ -241,7 +249,7 @@ else if (start.equalsIgnoreCase(SELECT))
241249
}
242250
while (StringUtils.equals(peek(t), COMMA));
243251

244-
query.fetch(selects.stream().collect(Collectors.joining(",")));
252+
query.fetch(String.join(",", selects));
245253

246254
// Allow EOF, EXPAND, WHERE or ORDER
247255
final String token = peek(t);
@@ -279,6 +287,9 @@ else if (token.equalsIgnoreCase(ORDER))
279287

280288
if (operator.equalsIgnoreCase(IS))
281289
{ // Unary expression
290+
if (notted)
291+
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
292+
282293
final boolean isNotNullExpr = takeIf(t, NOT);
283294

284295
expect(t, NULL);
@@ -349,54 +360,66 @@ else if (operator.equalsIgnoreCase(CONTAINS) || operator.equals(CONTAINS2))
349360
else
350361
group.notContains(start, val);
351362
}
352-
else if (operator.equalsIgnoreCase("eqref"))
353-
{
354-
if (!notted)
355-
group.eqRef(start, val);
356-
else
357-
group.neqRef(start, val);
358-
}
359-
else if (operator.equalsIgnoreCase("neqref"))
360-
{
361-
if (!notted)
362-
group.neqRef(start, val);
363-
else
364-
group.eqRef(start, val);
365-
}
366-
else if (operator.equalsIgnoreCase("leref"))
363+
else if (operator.length() >= 5 && StringUtils.endsWithIgnoreCase(operator, "ref"))
367364
{
368-
if (notted)
369-
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
365+
if (operator.equalsIgnoreCase("eqref"))
366+
{
367+
if (!notted)
368+
group.eqRef(start, val);
369+
else
370+
group.neqRef(start, val);
371+
}
372+
else if (operator.equalsIgnoreCase("neqref"))
373+
{
374+
if (!notted)
375+
group.neqRef(start, val);
376+
else
377+
group.eqRef(start, val);
378+
}
379+
else if (operator.equalsIgnoreCase("leref"))
380+
{
381+
if (notted)
382+
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
370383

371-
group.leRef(start, val);
372-
}
373-
else if (operator.equalsIgnoreCase("geref"))
374-
{
375-
if (notted)
376-
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
384+
group.leRef(start, val);
385+
}
386+
else if (operator.equalsIgnoreCase("geref"))
387+
{
388+
if (notted)
389+
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
377390

378-
group.geRef(start, val);
379-
}
380-
else if (operator.equalsIgnoreCase("ltref"))
381-
{
382-
if (notted)
383-
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
391+
group.geRef(start, val);
392+
}
393+
else if (operator.equalsIgnoreCase("ltref"))
394+
{
395+
if (notted)
396+
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
384397

385-
group.ltRef(start, val);
386-
}
387-
else if (operator.equalsIgnoreCase("gtref"))
388-
{
389-
if (notted)
390-
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
398+
group.ltRef(start, val);
399+
}
400+
else if (operator.equalsIgnoreCase("gtref"))
401+
{
402+
if (notted)
403+
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
391404

392-
group.gtRef(start, val);
405+
group.gtRef(start, val);
406+
}
407+
else
408+
{
409+
throw new IllegalArgumentException("Unknown operator: " + operator);
410+
}
393411
}
394412
else
395413
{
396414
if (notted)
397415
throw new IllegalArgumentException("Unexpected symbol NOT before " + operator);
398416

399-
switch (operator.toLowerCase(Locale.ROOT))
417+
// Allow case-insensitive matching for "eq", but leave "=" alone
418+
final String lcop = operator.length() == 1 || !Character.isAlphabetic(operator.charAt(0)) ?
419+
operator :
420+
operator.toLowerCase(Locale.ROOT);
421+
422+
switch (lcop)
400423
{
401424
case "=":
402425
case "eq":
@@ -515,8 +538,6 @@ private static List<String> tokenise(final String search)
515538
{
516539
List<String> tokens = new ArrayList<>();
517540

518-
char[] operators = new char[]{'=', '<', '>', '~', '!'};
519-
520541
for (int i = 0; i < search.length(); i++)
521542
{
522543
try
@@ -538,11 +559,11 @@ private static List<String> tokenise(final String search)
538559

539560
tokens.add(str);
540561
}
541-
else if (c == OPEN_BRACKET.charAt(0) || c == CLOSE_BRACKET.charAt(0) || c == COMMA.charAt(0))
562+
else if (c == OPEN_BRACKET_C || c == CLOSE_BRACKET_C || c == COMMA_C)
542563
{
543564
tokens.add(Character.toString(c));
544565
}
545-
else if (Character.isJavaIdentifierPart(c))
566+
else if (Character.isJavaIdentifierPart(c) || c == COLON_C)
546567
{
547568
final int start = i;
548569
// Search for: EOF, next char that is not isJavaIdentifierPart, a dot colon or square brackets
@@ -563,7 +584,7 @@ else if (Character.isJavaIdentifierPart(c))
563584
tokens.add(search.substring(start, i + 1));
564585
}
565586
}
566-
else if ((c == '-' && tokenPeekIs(search, i, '-')) || (c == '/' && tokenPeekIs(search, i, '/')))
587+
else if (tokenTupleMatch(search,i, c, '-','-') || tokenTupleMatch(search,i, c, '/','/'))
567588
{
568589
i++;
569590

@@ -576,7 +597,7 @@ else if ((c == '-' && tokenPeekIs(search, i, '-')) || (c == '/' && tokenPeekIs(s
576597
// Skip over all data
577598
i = endPos;
578599
}
579-
else if (c == '/' && tokenPeekIs(search, i, '*'))
600+
else if (tokenTupleMatch(search,i, c, '/','*'))
580601
{
581602
i++;
582603

@@ -591,11 +612,11 @@ else if (c == '/' && tokenPeekIs(search, i, '*'))
591612

592613
i = endPos +1;
593614
}
594-
else if (ArrayUtils.indexOf(operators, c) != -1)
615+
else if (ArrayUtils.indexOf(OPERATORS, c) != -1)
595616
{
596617
final int start = i;
597-
// Search for: EOF, next char that is not isJavaIdentifierPart / ":"
598-
while (i < search.length() && ArrayUtils.indexOf(operators, search.charAt(i)) != -1)
618+
// Consume a run of operators, stopping if we hit EOF
619+
while (i < search.length() && ArrayUtils.indexOf(OPERATORS, search.charAt(i)) != -1)
599620
{
600621
i++;
601622
}
@@ -628,12 +649,25 @@ else if (ArrayUtils.indexOf(operators, c) != -1)
628649
}
629650

630651

631-
public static boolean tokenPeekIs(final String s, final int i, final char c)
652+
/**
653+
* Tests if the current+next token matches (a,b)
654+
*
655+
* @param s source string
656+
* @param i current token position
657+
* @param curr the current token
658+
* @param a desired first token
659+
* @param b desired second token
660+
* @return
661+
*/
662+
private static boolean tokenTupleMatch(final String s, final int i, final char curr, final char a, final char b)
632663
{
633-
if (s.length() > i)
634-
return c == s.charAt(i + 1);
635-
else
636-
return false;
664+
return
665+
// current token matches
666+
curr == a &&
667+
// we are not at EOF
668+
s.length() > i &&
669+
// the next token matches
670+
b == s.charAt(i + 1);
637671
}
638672

639673
public static boolean isBareWordPart(final char c)

guice/common/src/main/java/com/peterphi/std/guice/restclient/resteasy/impl/PausableProxy.java

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@
33
import com.peterphi.std.guice.apploader.impl.GuiceBuilder;
44
import com.peterphi.std.guice.common.breaker.Breaker;
55
import com.peterphi.std.guice.restclient.exception.ServiceBreakerTripPreventsCallException;
6+
import com.peterphi.std.io.FileHelper;
67
import com.peterphi.std.threading.Deadline;
78
import com.peterphi.std.threading.Timeout;
89
import org.slf4j.Logger;
910
import org.slf4j.LoggerFactory;
1011

1112
import jakarta.ws.rs.BadRequestException;
13+
import java.io.InputStream;
14+
import java.io.Reader;
1215
import java.lang.reflect.InvocationHandler;
1316
import java.lang.reflect.InvocationTargetException;
1417
import java.lang.reflect.Method;
18+
import java.util.Base64;
1519
import java.util.concurrent.TimeUnit;
1620
import java.util.concurrent.atomic.AtomicInteger;
1721

@@ -86,10 +90,45 @@ public Object invoke(final Object proxy, final Method method, final Object[] arg
8690
final Throwable cause = e.getCause();
8791

8892
// Make sure we never throw a BadRequestException, because this bubbles all the way up and throws a 400 Bad Request error against our own service if uncaught
89-
if (cause instanceof BadRequestException)
90-
throw new RuntimeException("Remote service returned 400 Bad Request!", e);
93+
if (cause instanceof BadRequestException br)
94+
{
95+
final String methodName = method.getDeclaringClass().getSimpleName() + "::" + method.getName();
96+
97+
if (log.isWarnEnabled())
98+
{
99+
try
100+
{
101+
if (br.getResponse() != null && br.getResponse().hasEntity())
102+
{
103+
final Object entity = br.getResponse().getEntity();
104+
105+
final String body = switch (entity)
106+
{
107+
case InputStream is ->
108+
// TODO should read binary data and use heuristic to determine if text, otherwise base64 encode
109+
FileHelper.cat(is);
110+
case Reader r -> FileHelper.cat(r);
111+
case CharSequence cs -> cs.toString();
112+
case byte[] arr -> "byte[]: " + Base64.getEncoder().encodeToString(arr);
113+
case null -> "(null body)";
114+
default -> "Entity class=" + entity.getClass().getSimpleName() + ": " + entity;
115+
};
116+
117+
log.warn("HTTP Call {} Encountered 400 Bad Request error, response body: {}", methodName, body, br);
118+
}
119+
}
120+
catch (Throwable tt)
121+
{
122+
// ignore
123+
}
124+
}
125+
126+
throw new RuntimeException("Remote service call " + methodName + " returned 400 Bad Request!", br);
127+
}
91128
else
129+
{
92130
throw cause;
131+
}
93132
}
94133
}
95134

@@ -109,14 +148,7 @@ private void pause(final boolean fastFail)
109148
{
110149
while (isPaused() && deadline.isValid())
111150
{
112-
try
113-
{
114-
Thread.sleep(500);
115-
}
116-
catch (InterruptedException e)
117-
{
118-
return;
119-
}
151+
Timeout.ONE_SECOND.sleep(deadline);
120152
}
121153
}
122154
finally

0 commit comments

Comments
 (0)