20
20
import java .io .OutputStreamWriter ;
21
21
import java .io .Reader ;
22
22
import java .net .HttpURLConnection ;
23
+ import java .net .URI ;
23
24
import java .net .URISyntaxException ;
24
25
import java .nio .charset .Charset ;
25
26
import java .nio .charset .StandardCharsets ;
@@ -121,6 +122,8 @@ public class RDF4JProtocolSession extends SPARQLProtocolSession {
121
122
122
123
private long pingDelay = PINGDELAY ;
123
124
125
+ private int serverProtocolVersion = 0 ;
126
+
124
127
/**
125
128
* @deprecated Use {@link #RDF4JProtocolSession(HttpClient, ExecutorService)} instead
126
129
*/
@@ -165,6 +168,7 @@ public void setServerURL(String serverURL) {
165
168
}
166
169
167
170
this .serverURL = serverURL ;
171
+ this .serverProtocolVersion = 0 ; // side effect
168
172
}
169
173
170
174
public String getServerURL () {
@@ -275,6 +279,16 @@ public String getServerProtocol() throws IOException, RepositoryException, Unaut
275
279
}
276
280
}
277
281
282
+ private int getServerProtocolVersion () throws UnauthorizedException , RepositoryException , IOException {
283
+ if (serverProtocolVersion > 0 ) {
284
+ return serverProtocolVersion ;
285
+ }
286
+
287
+ var protocolVersionString = getServerProtocol ();
288
+ serverProtocolVersion = Integer .parseInt (protocolVersionString );
289
+ return serverProtocolVersion ;
290
+ }
291
+
278
292
/*-------------------------*
279
293
* Repository/context size *
280
294
*-------------------------*/
@@ -286,9 +300,8 @@ public long size(Resource... contexts) throws IOException, RepositoryException,
286
300
String transactionURL = getTransactionURL ();
287
301
final boolean useTransaction = transactionURL != null ;
288
302
289
- String baseLocation = useTransaction ? appendAction (transactionURL , Action .SIZE )
290
- : Protocol .getSizeLocation (getQueryURL ());
291
- URIBuilder url = new URIBuilder (baseLocation );
303
+ URIBuilder url = useTransaction ? getTxnActionURIBuilder (Action .SIZE )
304
+ : new URIBuilder (Protocol .getSizeLocation (getQueryURL ()));
292
305
293
306
String [] encodedContexts = Protocol .encodeContexts (contexts );
294
307
for (int i = 0 ; i < encodedContexts .length ; i ++) {
@@ -591,8 +604,8 @@ public void getStatements(Resource subj, IRI pred, Value obj, boolean includeInf
591
604
String transactionURL = getTransactionURL ();
592
605
final boolean useTransaction = transactionURL != null ;
593
606
594
- String baseLocation = useTransaction ? transactionURL : Protocol . getStatementsLocation ( getQueryURL ());
595
- URIBuilder url = new URIBuilder (baseLocation );
607
+ URIBuilder url = useTransaction ? getTxnActionURIBuilder ( Action . GET )
608
+ : new URIBuilder (Protocol . getStatementsLocation ( getQueryURL ()) );
596
609
597
610
if (subj != null ) {
598
611
url .setParameter (Protocol .SUBJECT_PARAM_NAME , Protocol .encodeValue (subj ));
@@ -607,9 +620,6 @@ public void getStatements(Resource subj, IRI pred, Value obj, boolean includeInf
607
620
url .addParameter (Protocol .CONTEXT_PARAM_NAME , encodedContext );
608
621
}
609
622
url .setParameter (Protocol .INCLUDE_INFERRED_PARAM_NAME , Boolean .toString (includeInferred ));
610
- if (useTransaction ) {
611
- url .setParameter (Protocol .ACTION_PARAM_NAME , Action .GET .toString ());
612
- }
613
623
614
624
HttpRequestBase method = useTransaction ? new HttpPut (url .build ()) : new HttpGet (url .build ());
615
625
method = applyAdditionalHeaders (method );
@@ -683,6 +693,24 @@ public synchronized void beginTransaction(TransactionSetting... transactionSetti
683
693
}
684
694
}
685
695
696
+ private URIBuilder getTxnActionURIBuilder (Action action )
697
+ throws RDF4JException , IOException , UnauthorizedException {
698
+ Objects .requireNonNull (action );
699
+ try {
700
+ if (getServerProtocolVersion () < 14 ) { // use legacy action parameter instead of dedicated action endpoint
701
+ URIBuilder builder = new URIBuilder (transactionURL );
702
+ builder .addParameter (Protocol .ACTION_PARAM_NAME , action .toString ());
703
+ return builder ;
704
+ }
705
+
706
+ URIBuilder builder = new URIBuilder (transactionURL + "/" + action .toString ().toLowerCase ());
707
+ return builder ;
708
+ } catch (URISyntaxException e ) {
709
+ logger .error ("could not create URL for transaction " + action , e );
710
+ throw new RuntimeException (e );
711
+ }
712
+ }
713
+
686
714
public synchronized void prepareTransaction () throws RDF4JException , IOException , UnauthorizedException {
687
715
checkRepositoryURL ();
688
716
@@ -692,9 +720,8 @@ public synchronized void prepareTransaction() throws RDF4JException, IOException
692
720
693
721
HttpPut method = null ;
694
722
try {
695
- URIBuilder url = new URIBuilder (transactionURL );
696
- url .addParameter (Protocol .ACTION_PARAM_NAME , Action .PREPARE .toString ());
697
- method = applyAdditionalHeaders (new HttpPut (url .build ()));
723
+ var uriBuilder = getTxnActionURIBuilder (Action .PREPARE );
724
+ method = applyAdditionalHeaders (new HttpPut (uriBuilder .build ()));
698
725
699
726
final HttpResponse response = execute (method );
700
727
try {
@@ -725,9 +752,8 @@ public synchronized void commitTransaction() throws RDF4JException, IOException,
725
752
726
753
HttpPut method = null ;
727
754
try {
728
- URIBuilder url = new URIBuilder (transactionURL );
729
- url .addParameter (Protocol .ACTION_PARAM_NAME , Action .COMMIT .toString ());
730
- method = applyAdditionalHeaders (new HttpPut (url .build ()));
755
+ var uriBuilder = getTxnActionURIBuilder (Action .COMMIT );
756
+ method = applyAdditionalHeaders (new HttpPut (uriBuilder .build ()));
731
757
732
758
final HttpResponse response = execute (method );
733
759
try {
@@ -804,11 +830,10 @@ void executeTransactionPing() {
804
830
if (transactionURL == null ) {
805
831
return ; // transaction has already been closed
806
832
}
807
- HttpPost method ;
808
833
try {
809
- URIBuilder url = new URIBuilder ( transactionURL );
810
- url . addParameter ( Protocol . ACTION_PARAM_NAME , Action . PING . toString ( ));
811
- method = applyAdditionalHeaders ( new HttpPost ( url . build ()));
834
+ var uriBuilder = getTxnActionURIBuilder ( Action . PING );
835
+ var method = applyAdditionalHeaders ( new HttpPost ( uriBuilder . build () ));
836
+
812
837
String text = EntityUtils .toString (executeOK (method ).getEntity ());
813
838
long timeout = Long .parseLong (text );
814
839
// clients should ping before server timeouts transaction
@@ -824,16 +849,16 @@ void executeTransactionPing() {
824
849
pingTransaction (); // reschedule
825
850
}
826
851
827
- /**
828
- * Appends the action as a parameter to the supplied url
829
- *
830
- * @param url a url on which to append the parameter. it is assumed the url has no parameters.
831
- * @param action the action to add as a parameter
832
- * @return the url parametrized with the supplied action
833
- */
834
- private String appendAction (String url , Action action ) {
835
- return url + "?" + Protocol .ACTION_PARAM_NAME + "=" + action .toString ();
836
- }
852
+ // /**
853
+ // * Appends the action as a parameter to the supplied url
854
+ // *
855
+ // * @param url a url on which to append the parameter. it is assumed the url has no parameters.
856
+ // * @param action the action to add as a parameter
857
+ // * @return the url parametrized with the supplied action
858
+ // */
859
+ // private String appendAction(String url, Action action) {
860
+ // return url + "?" + Protocol.ACTION_PARAM_NAME + "=" + action.toString();
861
+ // }
837
862
838
863
/**
839
864
* Sends a transaction list as serialized XML to the server.
@@ -938,9 +963,16 @@ protected HttpUriRequest getQueryMethod(QueryLanguage ql, String query, String b
938
963
RequestBuilder builder ;
939
964
String transactionURL = getTransactionURL ();
940
965
if (transactionURL != null ) {
941
- builder = RequestBuilder .put (transactionURL );
966
+ URI requestURI ;
967
+ try {
968
+ requestURI = getTxnActionURIBuilder (Action .QUERY ).build ();
969
+ } catch (URISyntaxException | IOException e ) {
970
+ logger .error ("could not create URL for transaction query" , e );
971
+ throw new RuntimeException (e );
972
+ }
973
+
974
+ builder = RequestBuilder .put (requestURI );
942
975
builder .setHeader ("Content-Type" , Protocol .SPARQL_QUERY_MIME_TYPE + "; charset=utf-8" );
943
- builder .addParameter (Protocol .ACTION_PARAM_NAME , Action .QUERY .toString ());
944
976
for (NameValuePair nvp : getQueryMethodParameters (ql , null , baseURI , dataset , includeInferred , maxQueryTime ,
945
977
bindings )) {
946
978
builder .addParameter (nvp );
@@ -971,9 +1003,17 @@ protected HttpUriRequest getUpdateMethod(QueryLanguage ql, String update, String
971
1003
RequestBuilder builder ;
972
1004
String transactionURL = getTransactionURL ();
973
1005
if (transactionURL != null ) {
974
- builder = RequestBuilder .put (transactionURL );
1006
+
1007
+ URI requestURI ;
1008
+ try {
1009
+ requestURI = getTxnActionURIBuilder (Action .UPDATE ).build ();
1010
+ } catch (URISyntaxException | IOException e ) {
1011
+ logger .error ("could not create URL for transaction update" , e );
1012
+ throw new RuntimeException (e );
1013
+ }
1014
+
1015
+ builder = RequestBuilder .put (requestURI );
975
1016
builder .addHeader ("Content-Type" , Protocol .SPARQL_UPDATE_MIME_TYPE + "; charset=utf-8" );
976
- builder .addParameter (Protocol .ACTION_PARAM_NAME , Action .UPDATE .toString ());
977
1017
for (NameValuePair nvp : getUpdateMethodParameters (ql , null , baseURI , dataset , includeInferred ,
978
1018
maxExecutionTime , bindings )) {
979
1019
builder .addParameter (nvp );
@@ -1061,36 +1101,28 @@ protected void upload(HttpEntity reqEntity, String baseURI, boolean overwrite, b
1061
1101
boolean useTransaction = transactionURL != null ;
1062
1102
1063
1103
try {
1064
-
1065
- String baseLocation = useTransaction ? transactionURL : Protocol .getStatementsLocation (getQueryURL ());
1066
- URIBuilder url = new URIBuilder (baseLocation );
1104
+ URIBuilder uriBuilder = useTransaction ? getTxnActionURIBuilder (action )
1105
+ : new URIBuilder (Protocol .getStatementsLocation (getQueryURL ()));
1067
1106
1068
1107
// Set relevant query parameters
1069
1108
for (String encodedContext : Protocol .encodeContexts (contexts )) {
1070
- url .addParameter (Protocol .CONTEXT_PARAM_NAME , encodedContext );
1109
+ uriBuilder .addParameter (Protocol .CONTEXT_PARAM_NAME , encodedContext );
1071
1110
}
1072
1111
if (baseURI != null && baseURI .trim ().length () != 0 ) {
1073
1112
String encodedBaseURI = Protocol .encodeValue (SimpleValueFactory .getInstance ().createIRI (baseURI ));
1074
- url .setParameter (Protocol .BASEURI_PARAM_NAME , encodedBaseURI );
1113
+ uriBuilder .setParameter (Protocol .BASEURI_PARAM_NAME , encodedBaseURI );
1075
1114
}
1076
1115
if (preserveNodeIds ) {
1077
- url .setParameter (Protocol .PRESERVE_BNODE_ID_PARAM_NAME , "true" );
1078
- }
1079
-
1080
- if (useTransaction ) {
1081
- if (action == null ) {
1082
- throw new IllegalArgumentException ("action can not be null on transaction operation" );
1083
- }
1084
- url .setParameter (Protocol .ACTION_PARAM_NAME , action .toString ());
1116
+ uriBuilder .setParameter (Protocol .PRESERVE_BNODE_ID_PARAM_NAME , "true" );
1085
1117
}
1086
1118
1087
1119
// Select appropriate HTTP method
1088
1120
HttpEntityEnclosingRequestBase method = null ;
1089
1121
try {
1090
1122
if (overwrite || useTransaction ) {
1091
- method = applyAdditionalHeaders (new HttpPut (url .build ()));
1123
+ method = applyAdditionalHeaders (new HttpPut (uriBuilder .build ()));
1092
1124
} else {
1093
- method = applyAdditionalHeaders (new HttpPost (url .build ()));
1125
+ method = applyAdditionalHeaders (new HttpPost (uriBuilder .build ()));
1094
1126
}
1095
1127
1096
1128
// Set payload
@@ -1217,4 +1249,9 @@ private <T extends HttpUriRequest> T applyAdditionalHeaders(T method) {
1217
1249
}
1218
1250
return method ;
1219
1251
}
1252
+
1253
+ private boolean useDeprecatedTxnActions ()
1254
+ throws UnauthorizedException , NumberFormatException , RepositoryException , IOException {
1255
+ return Integer .parseInt (getServerProtocol ()) < 14 ;
1256
+ }
1220
1257
}
0 commit comments