-
Notifications
You must be signed in to change notification settings - Fork 150
Expand file tree
/
Copy pathApplication.java
More file actions
2371 lines (2163 loc) · 108 KB
/
Application.java
File metadata and controls
2371 lines (2163 loc) · 108 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* Copyright 2019 Martynas Jusevičius <martynas@atomgraph.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.atomgraph.linkeddatahub;
import com.atomgraph.linkeddatahub.server.mapper.HttpHostConnectExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.InternalURLExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.MessagingExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.auth.webid.WebIDLoadingExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.auth.webid.InvalidWebIDURIExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.auth.AuthorizationExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.auth.AuthenticationExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.ForbiddenExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.auth.webid.WebIDCertificateExceptionMapper;
import com.atomgraph.client.MediaTypes;
import com.atomgraph.client.locator.PrefixMapper;
import org.apache.jena.ontology.OntDocumentManager;
import org.apache.jena.util.FileManager;
import org.apache.jena.util.LocationMapper;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.ServletConfig;
import jakarta.ws.rs.core.Context;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFFormat;
import org.apache.jena.riot.RDFWriterRegistry;
import com.atomgraph.client.mapper.ClientErrorExceptionMapper;
import com.atomgraph.client.util.DataManager;
import com.atomgraph.client.util.DataManagerImpl;
import com.atomgraph.client.vocabulary.AC;
import com.atomgraph.client.writer.function.UUID;
import com.atomgraph.core.exception.ConfigurationException;
import com.atomgraph.core.io.DatasetProvider;
import com.atomgraph.core.io.ModelProvider;
import com.atomgraph.core.io.QueryProvider;
import com.atomgraph.core.io.ResultSetProvider;
import com.atomgraph.core.io.UpdateRequestProvider;
import com.atomgraph.core.mapper.BadGatewayExceptionMapper;
import com.atomgraph.core.provider.QueryParamProvider;
import com.atomgraph.linkeddatahub.writer.factory.DataManagerFactory;
import com.atomgraph.server.vocabulary.LDT;
import com.atomgraph.server.mapper.NotFoundExceptionMapper;
import com.atomgraph.core.riot.RDFLanguages;
import com.atomgraph.core.riot.lang.RDFPostReaderFactory;
import com.atomgraph.core.vocabulary.A;
import com.atomgraph.linkeddatahub.server.mapper.auth.webid.InvalidWebIDPublicKeyExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.ModelExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.OntClassNotFoundExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.jena.QueryExecExceptionMapper;
import com.atomgraph.linkeddatahub.server.mapper.jena.RiotParseExceptionMapper;
import com.atomgraph.linkeddatahub.apps.model.AdminApplication;
import com.atomgraph.linkeddatahub.model.auth.Agent;
import com.atomgraph.linkeddatahub.model.CSVImport;
import com.atomgraph.linkeddatahub.apps.model.EndUserApplication;
import com.atomgraph.linkeddatahub.model.Service;
import com.atomgraph.linkeddatahub.writer.factory.xslt.XsltExecutableSupplier;
import com.atomgraph.linkeddatahub.writer.factory.XsltExecutableSupplierFactory;
import com.atomgraph.client.util.XsltResolver;
import com.atomgraph.linkeddatahub.client.GraphStoreClient;
import com.atomgraph.linkeddatahub.client.filter.ClientUriRewriteFilter;
import com.atomgraph.linkeddatahub.client.filter.JSONGRDDLFilter;
import com.atomgraph.linkeddatahub.client.filter.JSONGRDDLFilterProvider;
import com.atomgraph.linkeddatahub.imports.ImportExecutor;
import com.atomgraph.linkeddatahub.io.HtmlJsonLDReaderFactory;
import com.atomgraph.linkeddatahub.io.JsonLDReader;
import com.atomgraph.linkeddatahub.listener.EMailListener;
import com.atomgraph.linkeddatahub.writer.ModelXSLTWriter;
import com.atomgraph.linkeddatahub.model.Import;
import com.atomgraph.linkeddatahub.model.RDFImport;
import com.atomgraph.linkeddatahub.model.UserAccount;
import com.atomgraph.linkeddatahub.model.auth.Authorization;
import com.atomgraph.linkeddatahub.server.mapper.auth.webid.WebIDDelegationExceptionMapper;
import com.atomgraph.linkeddatahub.model.auth.impl.AgentImpl;
import com.atomgraph.linkeddatahub.model.auth.impl.AuthorizationImpl;
import com.atomgraph.linkeddatahub.model.impl.CSVImportImpl;
import com.atomgraph.linkeddatahub.model.impl.FileImpl;
import com.atomgraph.linkeddatahub.model.impl.ImportImpl;
import com.atomgraph.linkeddatahub.model.impl.RDFImportImpl;
import com.atomgraph.linkeddatahub.model.impl.UserAccountImpl;
import com.atomgraph.linkeddatahub.server.event.AuthorizationCreated;
import com.atomgraph.linkeddatahub.server.event.SignUp;
import com.atomgraph.linkeddatahub.server.factory.AgentContextFactory;
import com.atomgraph.linkeddatahub.server.factory.ApplicationFactory;
import com.atomgraph.linkeddatahub.server.factory.AuthorizationContextFactory;
import com.atomgraph.linkeddatahub.server.filter.request.ApplicationFilter;
import com.atomgraph.linkeddatahub.server.filter.request.auth.WebIDFilter;
import com.atomgraph.linkeddatahub.server.io.ValidatingModelProvider;
import com.atomgraph.server.mapper.ConfigurationExceptionMapper;
import com.atomgraph.linkeddatahub.server.factory.OntologyFactory;
import com.atomgraph.linkeddatahub.server.factory.ServiceFactory;
import com.atomgraph.linkeddatahub.server.filter.request.OntologyFilter;
import com.atomgraph.linkeddatahub.server.filter.request.ProxyRequestFilter;
import com.atomgraph.linkeddatahub.server.filter.request.AuthorizationFilter;
import com.atomgraph.linkeddatahub.server.filter.request.ContentLengthLimitFilter;
import com.atomgraph.linkeddatahub.server.filter.request.auth.ProxiedWebIDFilter;
import com.atomgraph.linkeddatahub.server.filter.response.CORSFilter;
import com.atomgraph.linkeddatahub.server.filter.response.ResponseHeadersFilter;
import com.atomgraph.linkeddatahub.server.filter.response.CacheInvalidationFilter;
import com.atomgraph.linkeddatahub.server.filter.response.XsltExecutableFilter;
import com.atomgraph.linkeddatahub.server.interceptor.RDFPostMediaTypeInterceptor;
import com.atomgraph.linkeddatahub.server.mapper.auth.oauth2.TokenExpiredExceptionMapper;
import com.atomgraph.linkeddatahub.server.model.impl.Dispatcher;
import com.atomgraph.linkeddatahub.server.security.AgentContext;
import com.atomgraph.linkeddatahub.server.security.AuthorizationContext;
import com.atomgraph.linkeddatahub.server.util.MessageBuilder;
import com.atomgraph.linkeddatahub.server.util.URLValidator;
import com.atomgraph.linkeddatahub.vocabulary.ACL;
import com.atomgraph.linkeddatahub.vocabulary.FOAF;
import com.atomgraph.linkeddatahub.vocabulary.LDH;
import com.atomgraph.linkeddatahub.vocabulary.LDHC;
import com.atomgraph.linkeddatahub.vocabulary.Google;
import com.atomgraph.linkeddatahub.vocabulary.ORCID;
import com.atomgraph.linkeddatahub.vocabulary.LAPP;
import com.atomgraph.linkeddatahub.writer.Mode;
import com.atomgraph.linkeddatahub.writer.ResultSetXSLTWriter;
import com.atomgraph.linkeddatahub.writer.XSLTWriterBase;
import com.atomgraph.linkeddatahub.writer.factory.ModeFactory;
import com.atomgraph.linkeddatahub.writer.function.DecodeURI;
import com.atomgraph.server.mapper.NotAcceptableExceptionMapper;
import com.atomgraph.server.mapper.OntologyExceptionMapper;
import com.atomgraph.server.mapper.jena.DatatypeFormatExceptionMapper;
import com.atomgraph.server.mapper.jena.QueryParseExceptionMapper;
import com.atomgraph.server.mapper.jena.RiotExceptionMapper;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.apache.jena.enhanced.BuiltinPersonalities;
import org.apache.jena.ontology.OntModelSpec;
import org.apache.jena.riot.RDFParserRegistry;
import org.slf4j.Logger;
import java.net.URI;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.ServiceLoader;
import java.util.Map;
import java.util.Properties;
import jakarta.mail.Authenticator;
import jakarta.mail.PasswordAuthentication;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import jakarta.servlet.ServletContext;
import javax.xml.transform.Source;
import org.apache.jena.ontology.Ontology;
import org.apache.jena.query.Dataset;
import org.apache.jena.query.Query;
import org.apache.jena.query.QueryExecution;
import org.apache.jena.query.QueryFactory;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.riot.RDFDataMgr;
import org.slf4j.LoggerFactory;
import com.atomgraph.server.mapper.SHACLConstraintViolationExceptionMapper;
import com.atomgraph.server.mapper.SPINConstraintViolationExceptionMapper;
import com.atomgraph.spinrdf.vocabulary.SP;
import com.github.jsonldjava.core.DocumentLoader;
import com.github.jsonldjava.core.JsonLdOptions;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import jakarta.mail.Address;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.ClientRequestFilter;
import jakarta.ws.rs.core.Response;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamSource;
import net.jodah.expiringmap.ExpiringMap;
import net.sf.saxon.om.TreeInfo;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XdmAtomicValue;
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltExecutable;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpHost;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpCoreContext;
import org.apache.jena.query.DatasetFactory;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.ResIterator;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.riot.resultset.ResultSetLang;
import org.apache.jena.riot.system.ErrorHandlerFactory;
import org.apache.jena.riot.system.ParserProfile;
import org.apache.jena.riot.system.RiotLib;
import org.apache.jena.sparql.graph.GraphReadOnly;
import org.apache.jena.vocabulary.DCTerms;
import org.apache.jena.vocabulary.LocationMappingVocab;
import org.apache.jena.vocabulary.RDF;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.apache.connector.ApacheClientProperties;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.RequestEntityProcessing;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.filter.HttpMethodOverrideFilter;
import org.glassfish.jersey.uri.UriComponent;
import org.xml.sax.SAXException;
/**
* JAX-RS application subclass.
* Used to configure the JAX-RS web application in <code>web.xml</code>.
*
* @author Martynas Jusevičius {@literal <martynas@atomgraph.com>}
* @see <a href="https://jersey.github.io/documentation/1.19.1/jax-rs.html#d4e186">Deploying a RESTful Web Service</a>
*/
public class Application extends ResourceConfig
{
private static final Logger log = LoggerFactory.getLogger(Application.class);
/**
* Path to the master XSLT stylesheet for server-side transformations.
* Package stylesheets are imported into this master stylesheet.
*/
public static final String MASTER_STYLESHEET_PATH = "/static/xsl/layout.xsl";
private final ExecutorService importThreadPool;
private final ServletConfig servletConfig;
private final EventBus eventBus = new EventBus();
private final DataManager dataManager;
private final Map<String, OntModelSpec> endUserOntModelSpecs;
private final MediaTypes mediaTypes;
private final Client client, externalClient, importClient, noCertClient;
private final Query documentTypeQuery, documentOwnerQuery, aclQuery, ownerAclQuery, webIDQuery, agentQuery, userAccountQuery, ontologyQuery; // no relative URIs
private final Integer maxGetRequestSize;
private final boolean preemptiveAuth;
private final Processor xsltProc = new Processor(false);
private final XsltCompiler xsltComp;
private final XsltExecutable xsltExec;
private final OntModelSpec ontModelSpec;
private final boolean cacheStylesheet;
private final boolean resolvingUncached;
private final URI baseURI, uploadRoot;
private final boolean invalidateCache;
private final Integer cookieMaxAge;
private final boolean enableLinkedDataProxy;
private final boolean allowInternalUrls;
private final URLValidator urlValidator;
private final Integer maxContentLength;
private final Address notificationAddress;
private final Authenticator authenticator;
private final Properties emailProperties = new Properties();
private final KeyStore keyStore, trustStore;
private final URI secretaryWebIDURI;
private final List<Locale> supportedLanguages;
private final ExpiringMap<URI, Model> webIDmodelCache = ExpiringMap.builder().expiration(1, TimeUnit.DAYS).build(); // TO-DO: config for the expiration period?
private final ExpiringMap<String, Model> oidcModelCache = ExpiringMap.builder().variableExpiration().build();
private final ExpiringMap<String, jakarta.json.JsonObject> jwksCache = ExpiringMap.builder().expiration(1, TimeUnit.DAYS).build(); // Cache JWKS responses
private final Map<URI, XsltExecutable> xsltExecutableCache = new ConcurrentHashMap<>();
private final MessageDigest messageDigest;
private final boolean enableWebIDSignUp;
private final String oidcRefreshTokensPropertiesPath;
private final Properties oidcRefreshTokens;
private final URI contextDatasetURI;
private final Dataset contextDataset;
private final URI frontendProxy;
private final URI backendProxyAdmin;
private final URI backendProxyEndUser;
private Map<String, com.atomgraph.linkeddatahub.model.ServiceContext> serviceContextMap;
/**
* Constructs system application and configures it using sevlet config.
*
* @param servletConfig servlet config
* @throws URISyntaxException throw on URI syntax errors
* @throws MalformedURLException thrown on URL syntax errors
* @throws IOException thrown on I/O errors
*/
public Application(@Context ServletConfig servletConfig) throws URISyntaxException, MalformedURLException, IOException
{
this(servletConfig,
new MediaTypes(),
servletConfig.getServletContext().getInitParameter(A.maxGetRequestSize.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(A.maxGetRequestSize.getURI())) : null,
servletConfig.getServletContext().getInitParameter(A.cacheModelLoads.getURI()) != null ? Boolean.parseBoolean(servletConfig.getServletContext().getInitParameter(A.cacheModelLoads.getURI())) : true,
servletConfig.getServletContext().getInitParameter(A.preemptiveAuth.getURI()) != null ? Boolean.parseBoolean(servletConfig.getServletContext().getInitParameter(A.preemptiveAuth.getURI())) : false,
new PrefixMapper(servletConfig.getServletContext().getInitParameter(AC.prefixMapping.getURI()) != null ? servletConfig.getServletContext().getInitParameter(AC.prefixMapping.getURI()) : null),
servletConfig.getServletContext().getInitParameter(LDHC.contextDataset.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.contextDataset.getURI()) : null,
com.atomgraph.client.Application.getSource(servletConfig.getServletContext(), servletConfig.getServletContext().getInitParameter(AC.stylesheet.getURI()) != null ? servletConfig.getServletContext().getInitParameter(AC.stylesheet.getURI()) : null),
servletConfig.getServletContext().getInitParameter(AC.cacheStylesheet.getURI()) != null ? Boolean.parseBoolean(servletConfig.getServletContext().getInitParameter(AC.cacheStylesheet.getURI())) : false,
servletConfig.getServletContext().getInitParameter(AC.resolvingUncached.getURI()) != null ? Boolean.parseBoolean(servletConfig.getServletContext().getInitParameter(AC.resolvingUncached.getURI())) : true,
servletConfig.getServletContext().getInitParameter(LDHC.clientKeyStore.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.clientKeyStore.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.clientKeyStorePassword.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.clientKeyStorePassword.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.secretaryCertAlias.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.secretaryCertAlias.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.clientTrustStore.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.clientTrustStore.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.clientTrustStorePassword.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.clientTrustStorePassword.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.documentTypeQuery.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.documentTypeQuery.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.documentOwnerQuery.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.documentOwnerQuery.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.aclQuery.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.aclQuery.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.ownerAclQuery.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.ownerAclQuery.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.webIDQuery.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.webIDQuery.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.agentQuery.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.agentQuery.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.userAccountQuery.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.userAccountQuery.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.ontologyQuery.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.ontologyQuery.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.baseUri.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.baseUri.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.proxyScheme.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.proxyScheme.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.proxyHost.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.proxyHost.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.proxyPort.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.proxyPort.getURI())) : null,
servletConfig.getServletContext().getInitParameter(LDHC.uploadRoot.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.uploadRoot.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.invalidateCache.getURI()) != null ? Boolean.parseBoolean(servletConfig.getServletContext().getInitParameter(LDHC.invalidateCache.getURI())) : false,
servletConfig.getServletContext().getInitParameter(LDHC.cookieMaxAge.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.cookieMaxAge.getURI())) : null,
servletConfig.getServletContext().getInitParameter(LDHC.enableLinkedDataProxy.getURI()) != null ? Boolean.parseBoolean(servletConfig.getServletContext().getInitParameter(LDHC.enableLinkedDataProxy.getURI())) : true,
System.getProperty("com.atomgraph.linkeddatahub.allowInternalUrls") != null ? Boolean.parseBoolean(System.getProperty("com.atomgraph.linkeddatahub.allowInternalUrls")) :
servletConfig.getServletContext().getInitParameter(LDHC.allowInternalUrls.getURI()) != null ? Boolean.parseBoolean(servletConfig.getServletContext().getInitParameter(LDHC.allowInternalUrls.getURI())) : false,
servletConfig.getServletContext().getInitParameter(LDHC.maxContentLength.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.maxContentLength.getURI())) : null,
servletConfig.getServletContext().getInitParameter(LDHC.maxConnPerRoute.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.maxConnPerRoute.getURI())) : null,
servletConfig.getServletContext().getInitParameter(LDHC.maxTotalConn.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.maxTotalConn.getURI())) : null,
servletConfig.getServletContext().getInitParameter(LDHC.maxRequestRetries.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.maxRequestRetries.getURI())) : null,
servletConfig.getServletContext().getInitParameter(LDHC.maxImportThreads.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.maxImportThreads.getURI())) : null,
servletConfig.getServletContext().getInitParameter(LDHC.notificationAddress.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.notificationAddress.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.supportedLanguages.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.supportedLanguages.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.enableWebIDSignUp.getURI()) != null ? Boolean.parseBoolean(servletConfig.getServletContext().getInitParameter(LDHC.enableWebIDSignUp.getURI())) : true,
servletConfig.getServletContext().getInitParameter(LDHC.oidcRefreshTokens.getURI()),
servletConfig.getServletContext().getInitParameter(LDHC.frontendProxy.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.frontendProxy.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.backendProxyAdmin.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.backendProxyAdmin.getURI()) : null,
servletConfig.getServletContext().getInitParameter(LDHC.backendProxyEndUser.getURI()) != null ? servletConfig.getServletContext().getInitParameter(LDHC.backendProxyEndUser.getURI()) : null,
servletConfig.getServletContext().getInitParameter("mail.user") != null ? servletConfig.getServletContext().getInitParameter("mail.user") : null,
servletConfig.getServletContext().getInitParameter("mail.password") != null ? servletConfig.getServletContext().getInitParameter("mail.password") : null,
servletConfig.getServletContext().getInitParameter("mail.smtp.host") != null ? servletConfig.getServletContext().getInitParameter("mail.smtp.host") : null,
servletConfig.getServletContext().getInitParameter("mail.smtp.port") != null ? servletConfig.getServletContext().getInitParameter("mail.smtp.port") : null,
servletConfig.getServletContext().getInitParameter(Google.clientID.getURI()) != null ? servletConfig.getServletContext().getInitParameter(Google.clientID.getURI()) : null,
servletConfig.getServletContext().getInitParameter(Google.clientSecret.getURI()) != null ? servletConfig.getServletContext().getInitParameter(Google.clientSecret.getURI()) : null,
servletConfig.getServletContext().getInitParameter(ORCID.clientID.getURI()) != null ? servletConfig.getServletContext().getInitParameter(ORCID.clientID.getURI()) : null,
servletConfig.getServletContext().getInitParameter(ORCID.clientSecret.getURI()) != null ? servletConfig.getServletContext().getInitParameter(ORCID.clientSecret.getURI()) : null
);
}
/**
* Constructs and configures system application.
*
* @param servletConfig servlet config
* @param mediaTypes supported media types
* @param maxGetRequestSize maximum <code>GET</code> request size
* @param cacheModelLoads true if model loads should be cached
* @param preemptiveAuth true if HTTP Basic auth credentials should be sent preemptively
* @param locationMapper Jena's <code>LocationMapper</code> instance
* @param contextDatasetURIString location of the context dataset
* @param stylesheet stylesheet URI
* @param cacheStylesheet true if stylesheet should be cached
* @param resolvingUncached true if XLST processor should dereference URLs that are not cached
* @param clientKeyStoreURIString location of the client's keystore
* @param clientKeyStorePassword client keystore's password
* @param secretaryCertAlias alias of the secretary's certificate
* @param clientTrustStoreURIString location of the client's truststore
* @param clientTrustStorePassword client truststore's password
* @param documentTypeQueryString SPARQL string of the document type query
* @param documentOwnerQueryString SPARQL string of the document owner query
* @param aclQueryString SPARQL string of the ACL query
* @param ownerAclQueryString SPARQL string of the owner's ACL query
* @param webIDQueryString SPARQL string of the WebID validation query
* @param agentQueryString SPARQL string of the <code>Agent</code> lookup query
* @param userAccountQueryString SPARQL string of the <code>UserAccount</code> lookup query
* @param ontologyQueryString SPARQL string of the ontology load query
* @param baseURIString system base URI
* @param proxyScheme client's URI rewrite scheme
* @param proxyHostname client's URI rewrite hostname
* @param proxyPort client's URI rewrite port
* @param uploadRootString location of the root folder for file uploads
* @param invalidateCache true if Varnish proxy cache should be invalidated
* @param cookieMaxAge max age of auth cookies
* @param enableLinkedDataProxy true if Linked Data proxy is enabled
* @param allowInternalUrls true if internal/private network URLs are allowed (disables SSRF protection)
* @param maxContentLength maximum size of request entity
* @param maxConnPerRoute maximum client connections per rout
* @param maxTotalConn maximum total client connections
* @param maxRequestRetries maximum number of times that the HTTP client will retry a request
* @param maxImportThreads maximum number of threads used for asynchronous imports
* @param notificationAddressString email address used to send notifications
* @param supportedLanguageCodes comma-separated codes of supported languages
* @param enableWebIDSignUp true if WebID signup is enabled
* @param oidcRefreshTokensPropertiesPath path to the properties file with OIDC refresh tokens
* @param mailUser username of the SMTP email server
* @param mailPassword password of the SMTP email server
* @param smtpHost hostname of the SMTP email server
* @param smtpPort port of the SMTP email server
* @param googleClientID client ID for Google's OAuth
* @param googleClientSecret client secret for Google's OAuth
* @param orcidClientID client ID for ORCID's OAuth
* @param orcidClientSecret client secret for ORCID's OAuth
* @param frontendProxyString frontend (Varnish) proxy URI used for cache invalidation BAN requests, or null
* @param backendProxyAdminString backend proxy URI for the admin SPARQL service (endpoint URI rewriting + cache invalidation), or null
* @param backendProxyEndUserString backend proxy URI for the end-user SPARQL service (endpoint URI rewriting + cache invalidation), or null
*/
public Application(final ServletConfig servletConfig, final MediaTypes mediaTypes,
final Integer maxGetRequestSize, final boolean cacheModelLoads, final boolean preemptiveAuth,
final LocationMapper locationMapper, final String contextDatasetURIString,
final Source stylesheet, final boolean cacheStylesheet, final boolean resolvingUncached,
final String clientKeyStoreURIString, final String clientKeyStorePassword,
final String secretaryCertAlias,
final String clientTrustStoreURIString, final String clientTrustStorePassword,
final String documentTypeQueryString, final String documentOwnerQueryString, final String aclQueryString, final String ownerAclQueryString,
final String webIDQueryString, final String agentQueryString, final String userAccountQueryString, final String ontologyQueryString,
final String baseURIString, final String proxyScheme, final String proxyHostname, final Integer proxyPort,
final String uploadRootString, final boolean invalidateCache,
final Integer cookieMaxAge, final boolean enableLinkedDataProxy, final boolean allowInternalUrls, final Integer maxContentLength,
final Integer maxConnPerRoute, final Integer maxTotalConn, final Integer maxRequestRetries, final Integer maxImportThreads,
final String notificationAddressString, final String supportedLanguageCodes, final boolean enableWebIDSignUp, final String oidcRefreshTokensPropertiesPath,
final String frontendProxyString, final String backendProxyAdminString, final String backendProxyEndUserString,
final String mailUser, final String mailPassword, final String smtpHost, final String smtpPort,
final String googleClientID, final String googleClientSecret,
final String orcidClientID, final String orcidClientSecret)
{
if (contextDatasetURIString == null)
{
if (log.isErrorEnabled()) log.error("Context dataset URI '{}' not configured", LDHC.contextDataset.getURI());
throw new ConfigurationException(LDHC.contextDataset);
}
this.contextDatasetURI = URI.create(contextDatasetURIString);
this.frontendProxy = frontendProxyString != null ? URI.create(frontendProxyString) : null;
this.backendProxyAdmin = backendProxyAdminString != null ? URI.create(backendProxyAdminString) : null;
this.backendProxyEndUser = backendProxyEndUserString != null ? URI.create(backendProxyEndUserString) : null;
if (clientKeyStoreURIString == null)
{
if (log.isErrorEnabled()) log.error("Client key store ({}) not configured", LDHC.clientKeyStore.getURI());
throw new ConfigurationException(LDHC.clientKeyStore);
}
if (secretaryCertAlias == null)
{
if (log.isErrorEnabled()) log.error("Secretary client certificate alias ({}) not configured", LDHC.secretaryCertAlias.getURI());
throw new ConfigurationException(LDHC.secretaryCertAlias);
}
if (clientTrustStoreURIString == null)
{
if (log.isErrorEnabled()) log.error("Client truststore store ({}) not configured", LDHC.clientTrustStore.getURI());
throw new ConfigurationException(LDHC.clientTrustStore);
}
if (documentTypeQueryString == null)
{
if (log.isErrorEnabled()) log.error("Document type SPARQL query is not configured properly");
throw new ConfigurationException(LDHC.documentTypeQuery);
}
this.documentTypeQuery = QueryFactory.create(documentTypeQueryString);
if (documentOwnerQueryString == null)
{
if (log.isErrorEnabled()) log.error("Document owner SPARQL query is not configured properly");
throw new ConfigurationException(LDHC.documentOwnerQuery);
}
this.documentOwnerQuery = QueryFactory.create(documentOwnerQueryString);
if (aclQueryString == null)
{
if (log.isErrorEnabled()) log.error("ACL SPARQL query is not configured properly");
throw new ConfigurationException(LDHC.aclQuery);
}
this.aclQuery = QueryFactory.create(aclQueryString);
if (ownerAclQueryString == null)
{
if (log.isErrorEnabled()) log.error("Owner's ACL SPARQL query is not configured properly");
throw new ConfigurationException(LDHC.ownerAclQuery);
}
this.ownerAclQuery = QueryFactory.create(ownerAclQueryString);
if (webIDQueryString == null)
{
if (log.isErrorEnabled()) log.error("WebID SPARQL query is not configured properly");
throw new ConfigurationException(LDHC.webIDQuery);
}
this.webIDQuery = QueryFactory.create(webIDQueryString);
if (agentQueryString == null)
{
if (log.isErrorEnabled()) log.error("Agent SPARQL query is not configured properly");
throw new ConfigurationException(LDHC.agentQuery);
}
this.agentQuery = QueryFactory.create(agentQueryString);
if (userAccountQueryString == null)
{
if (log.isErrorEnabled()) log.error("UserAccount SPARQL query is not configured properly");
throw new ConfigurationException(LDHC.userAccountQuery);
}
this.userAccountQuery = QueryFactory.create(userAccountQueryString);
if (ontologyQueryString == null)
{
if (log.isErrorEnabled()) log.error("Ontology SPARQL query is not configured properly");
throw new ConfigurationException(LDHC.ontologyQuery);
}
this.ontologyQuery = QueryFactory.create(ontologyQueryString);
if (baseURIString == null)
{
if (log.isErrorEnabled()) log.error("Base URI property '{}' not configured", LDHC.baseUri.getURI());
throw new ConfigurationException(LDHC.baseUri);
}
baseURI = URI.create(baseURIString);
if (uploadRootString == null)
{
if (log.isErrorEnabled()) log.error("Upload root ({}) not configured", LDHC.uploadRoot.getURI());
throw new ConfigurationException(LDHC.uploadRoot);
}
if (cookieMaxAge == null)
{
if (log.isErrorEnabled()) log.error("JWT cookie max age property '{}' not configured", LDHC.cookieMaxAge.getURI());
throw new ConfigurationException(LDHC.cookieMaxAge);
}
this.cookieMaxAge = cookieMaxAge;
if (maxImportThreads == null)
{
if (log.isErrorEnabled()) log.error("Max import thread count property '{}' not configured", LDHC.maxImportThreads.getURI());
throw new ConfigurationException(LDHC.maxImportThreads);
}
this.importThreadPool = Executors.newFixedThreadPool(maxImportThreads);
servletConfig.getServletContext().setAttribute(LDHC.maxImportThreads.getURI(), importThreadPool); // used in ImportListener to shutdown the thread pool
if (supportedLanguageCodes == null)
{
if (log.isErrorEnabled()) log.error("Supported languages ({}) not configured", LDHC.supportedLanguages.getURI());
throw new ConfigurationException(LDHC.supportedLanguages);
}
this.supportedLanguages = Arrays.asList(supportedLanguageCodes.split(",")).stream().map(code -> Locale.forLanguageTag(code)).collect(Collectors.toList());
this.servletConfig = servletConfig;
this.mediaTypes = mediaTypes;
this.maxGetRequestSize = maxGetRequestSize;
this.preemptiveAuth = preemptiveAuth;
this.cacheStylesheet = cacheStylesheet;
this.resolvingUncached = resolvingUncached;
this.enableLinkedDataProxy = enableLinkedDataProxy;
this.allowInternalUrls = allowInternalUrls;
this.urlValidator = new URLValidator(allowInternalUrls);
this.maxContentLength = maxContentLength;
this.invalidateCache = invalidateCache;
this.enableWebIDSignUp = enableWebIDSignUp;
this.oidcRefreshTokensPropertiesPath = oidcRefreshTokensPropertiesPath;
this.oidcRefreshTokens = new Properties();
if (googleClientID != null) this.property(Google.clientID.getURI(), googleClientID);
if (googleClientSecret != null) this.property(Google.clientSecret.getURI(), googleClientSecret);
if (orcidClientID != null) this.property(ORCID.clientID.getURI(), orcidClientID);
if (orcidClientSecret != null) this.property(ORCID.clientSecret.getURI(), orcidClientSecret);
try
{
this.uploadRoot = new URI(uploadRootString);
}
catch (URISyntaxException ex)
{
if (log.isErrorEnabled()) log.error("Upload root URI syntax error: {}", ex);
throw new IllegalStateException(ex);
}
if (googleClientID != null && oidcRefreshTokensPropertiesPath == null)
{
if (log.isErrorEnabled()) log.error("Google OIDC signup is enabled (clientID client is provided) but refresh token cache is not configured (ldhc:oidcRefreshTokens)");
throw new IllegalStateException("Google OIDC signup is enabled (clientID client is provided) but refresh token cache is not configured (ldhc:oidcRefreshTokens)");
}
if (oidcRefreshTokensPropertiesPath != null)
{
try (InputStream propertiesStream = new FileInputStream(oidcRefreshTokensPropertiesPath))
{
if (propertiesStream == null)
{
if (log.isErrorEnabled()) log.error(".properties file with OIDC refresh tokens not found (ldhc:oidcRefreshTokens)");
throw new IllegalStateException(".properties file with OIDC refresh tokens not found (ldhc:oidcRefreshTokens)");
}
this.oidcRefreshTokens.load(propertiesStream);
}
catch (IOException ex)
{
if (log.isErrorEnabled()) log.error("Cannot read .properties file with OIDC refresh tokens: {}", ex);
throw new IllegalStateException(ex);
}
}
if (notificationAddressString != null)
{
try
{
InternetAddress[] notificationAddresses = InternetAddress.parse(notificationAddressString);
// if (notificationAddresses.size() == 0) throw Exception...
notificationAddress = notificationAddresses[0];
}
catch (AddressException ex)
{
throw new IllegalStateException(ex);
}
}
else notificationAddress = null;
try
{
javax.xml.parsers.SAXParserFactory factory = javax.xml.parsers.SAXParserFactory.newInstance();
javax.xml.parsers.SAXParser parser = factory.newSAXParser();
org.xml.sax.XMLReader reader = parser.getXMLReader();
if (log.isDebugEnabled()) log.debug("SAXParserFactory class: {}", factory.getClass().getName());
if (log.isDebugEnabled()) log.debug("XMLReader class: {}", reader.getClass().getName());
}
catch (ParserConfigurationException | SAXException e)
{
if (log.isErrorEnabled()) log.error("Failed to get XML parser info", e);
}
// add RDF/POST reader
RDFLanguages.register(RDFLanguages.RDFPOST);
RDFParserRegistry.registerLangTriples(RDFLanguages.RDFPOST, new RDFPostReaderFactory());
// register ResultSet languages until we start using Jena 5.x with https://github.com/apache/jena/pull/2510
RDFLanguages.register(ResultSetLang.RS_XML);
RDFLanguages.register(ResultSetLang.RS_JSON);
RDFLanguages.register(ResultSetLang.RS_CSV);
RDFLanguages.register(ResultSetLang.RS_TSV);
RDFLanguages.register(ResultSetLang.RS_Thrift);
RDFLanguages.register(ResultSetLang.RS_Protobuf);
// Not output-only text.
RDFLanguages.register(ResultSetLang.RS_None);
// add HTML/JSON-LD reader
DocumentLoader documentLoader = new DocumentLoader();
JsonLdOptions jsonLdOptions = new JsonLdOptions();
try (InputStream contextStream = servletConfig.getServletContext().getResourceAsStream("/WEB-INF/classes/com/atomgraph/linkeddatahub/schema.org.jsonldcontext.json"))
{
String jsonContext = new String(contextStream.readAllBytes(), StandardCharsets.UTF_8);
documentLoader.addInjectedDoc("http://schema.org", jsonContext);
documentLoader.addInjectedDoc("https://schema.org", jsonContext);
jsonLdOptions.setDocumentLoader(documentLoader);
ParserProfile profile = RiotLib.profile(HtmlJsonLDReaderFactory.HTML, null, ErrorHandlerFactory.getDefaultErrorHandler());
RDFLanguages.register(HtmlJsonLDReaderFactory.HTML);
RDFParserRegistry.registerLangTriples(HtmlJsonLDReaderFactory.HTML,
new HtmlJsonLDReaderFactory(new JsonLDReader(Lang.JSONLD, profile, profile.getErrorHandler()), jsonLdOptions));
}
catch (IOException ex)
{
if (log.isErrorEnabled()) log.error("schema.org @context not found", ex);
}
// register plain RDF/XML writer as default
RDFWriterRegistry.register(Lang.RDFXML, RDFFormat.RDFXML_PLAIN);
// initialize mapping for locally stored vocabularies
LocationMapper.setGlobalLocationMapper(locationMapper);
if (log.isTraceEnabled()) log.trace("LocationMapper.get(): {}", locationMapper);
try
{
this.contextDataset = getDataset(servletConfig.getServletContext(), contextDatasetURI);
keyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream keyStoreInputStream = new FileInputStream(new java.io.File(new URI(clientKeyStoreURIString))))
{
keyStore.load(keyStoreInputStream, clientKeyStorePassword.toCharArray());
}
trustStore = KeyStore.getInstance("JKS");
try (FileInputStream trustStoreInputStream = new FileInputStream(new java.io.File(new URI(clientTrustStoreURIString))))
{
trustStore.load(trustStoreInputStream, clientTrustStorePassword.toCharArray());
}
client = getClient(keyStore, clientKeyStorePassword, trustStore, maxConnPerRoute, maxTotalConn, null, false);
externalClient = getClient(keyStore, clientKeyStorePassword, trustStore, maxConnPerRoute, maxTotalConn, null, false);
importClient = getClient(keyStore, clientKeyStorePassword, trustStore, maxConnPerRoute, maxTotalConn, maxRequestRetries, true);
noCertClient = getNoCertClient(trustStore, maxConnPerRoute, maxTotalConn, maxRequestRetries);
if (maxContentLength != null)
{
client.register(new ContentLengthLimitFilter(maxContentLength));
externalClient.register(new ContentLengthLimitFilter(maxContentLength));
importClient.register(new ContentLengthLimitFilter(maxContentLength));
noCertClient.register(new ContentLengthLimitFilter(maxContentLength));
}
if (proxyHostname != null)
{
ClientRequestFilter rewriteFilter = new ClientUriRewriteFilter(baseURI.getHost(), proxyScheme, proxyHostname, proxyPort); // proxyPort can be null
client.register(rewriteFilter);
externalClient.register(rewriteFilter);
importClient.register(rewriteFilter);
noCertClient.register(rewriteFilter);
}
Certificate secretaryCert = keyStore.getCertificate(secretaryCertAlias);
if (secretaryCert == null)
{
if (log.isErrorEnabled()) log.error("Secretary certificate with alias {} does not exist in client keystore {}", secretaryCertAlias, clientKeyStoreURIString);
throw new IllegalStateException(new CertificateException("Secretary certificate with alias '" + secretaryCertAlias + "' does not exist in client keystore '" + clientKeyStoreURIString + "'"));
}
if (!(secretaryCert instanceof X509Certificate))
{
if (log.isErrorEnabled()) log.error("Secretary certificate with alias {} is not a X509Certificate", secretaryCertAlias);
throw new IllegalStateException(new CertificateException("Secretary certificate with alias " + secretaryCertAlias + " is not a X509Certificate"));
}
X509Certificate secretaryX509Cert = (X509Certificate)secretaryCert;
secretaryX509Cert.checkValidity();// check if secretary WebID client certificate is valid
secretaryWebIDURI = WebIDFilter.getWebIDURI(secretaryX509Cert);
if (secretaryWebIDURI == null)
{
if (log.isErrorEnabled()) log.error("Secretary certificate with alias {} is not a valid WebID sertificate (SNA URI is missing)", secretaryCertAlias);
throw new IllegalStateException(new CertificateException("Secretary certificate with alias " + secretaryCertAlias + " not a valid WebID sertificate (SNA URI is missing)"));
}
SP.init(BuiltinPersonalities.model);
BuiltinPersonalities.model.add(Authorization.class, AuthorizationImpl.factory);
BuiltinPersonalities.model.add(Agent.class, AgentImpl.factory);
BuiltinPersonalities.model.add(UserAccount.class, UserAccountImpl.factory);
BuiltinPersonalities.model.add(AdminApplication.class, new com.atomgraph.linkeddatahub.apps.model.admin.impl.ApplicationImplementation());
BuiltinPersonalities.model.add(EndUserApplication.class, new com.atomgraph.linkeddatahub.apps.model.end_user.impl.ApplicationImplementation());
BuiltinPersonalities.model.add(com.atomgraph.linkeddatahub.apps.model.Application.class, new com.atomgraph.linkeddatahub.apps.model.impl.ApplicationImplementation());
BuiltinPersonalities.model.add(com.atomgraph.linkeddatahub.apps.model.Dataset.class, new com.atomgraph.linkeddatahub.apps.model.impl.DatasetImplementation());
BuiltinPersonalities.model.add(com.atomgraph.linkeddatahub.apps.model.Package.class, new com.atomgraph.linkeddatahub.apps.model.impl.PackageImplementation());
BuiltinPersonalities.model.add(Service.class, new com.atomgraph.linkeddatahub.model.impl.ServiceImplementation());
BuiltinPersonalities.model.add(Import.class, ImportImpl.factory);
BuiltinPersonalities.model.add(RDFImport.class, RDFImportImpl.factory);
BuiltinPersonalities.model.add(CSVImport.class, CSVImportImpl.factory);
BuiltinPersonalities.model.add(com.atomgraph.linkeddatahub.model.File.class, FileImpl.factory);
// Build ServiceContext map: keyed by service URI, proxy derived from the app type that references each service.
// Iterating ldt:service statements (app → service) naturally excludes orphan services.
serviceContextMap = new HashMap<>();
org.apache.jena.rdf.model.Model ctxUnion = contextDataset.getUnionModel();
org.apache.jena.rdf.model.StmtIterator serviceIt = ctxUnion.listStatements(null, LDT.service, (org.apache.jena.rdf.model.RDFNode) null);
try
{
while (serviceIt.hasNext())
{
org.apache.jena.rdf.model.Statement stmt = serviceIt.nextStatement();
Resource app = stmt.getSubject();
Resource svcResource = stmt.getResource();
URI proxy;
if (app.hasProperty(RDF.type, LAPP.AdminApplication))
proxy = backendProxyAdmin;
else if (app.hasProperty(RDF.type, LAPP.EndUserApplication))
proxy = backendProxyEndUser;
else
continue;
serviceContextMap.put(svcResource.getURI(),
new com.atomgraph.linkeddatahub.model.ServiceContext(svcResource.as(com.atomgraph.linkeddatahub.model.Service.class), noCertClient, mediaTypes, maxGetRequestSize, proxy));
}
}
finally
{
serviceIt.close();
}
// TO-DO: config property for cacheModelLoads
endUserOntModelSpecs = new HashMap<>();
dataManager = new DataManagerImpl(locationMapper, new HashMap<>(), GraphStoreClient.create(client, mediaTypes), cacheModelLoads, preemptiveAuth, resolvingUncached);
ontModelSpec = OntModelSpec.OWL_MEM_RDFS_INF;
ontModelSpec.setImportModelGetter(dataManager);
OntDocumentManager.getInstance().setFileManager((FileManager)dataManager);
OntDocumentManager.getInstance().setCacheModels(true); // need to re-set after changing FileManager
ontModelSpec.setDocumentManager(OntDocumentManager.getInstance());
if (mailUser != null && mailPassword != null) // enable SMTP authentication
{
emailProperties.put("mail.smtp.auth", "true");
emailProperties.put("mail.smtp.starttls.enable", "true"); // connect via TLS https://support.google.com/a/answer/2956491?hl=en
authenticator = new Authenticator()
{
@Override
protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(mailUser, mailPassword);
}
};
}
else authenticator = null;
if (smtpHost == null) throw new IllegalStateException(new IllegalStateException("Cannot initialize email service: SMTP host not configured"));
if (smtpPort == null) throw new IllegalStateException(new IllegalStateException("Cannot initialize email service: SMTP port not configured"));
emailProperties.put("mail.smtp.host", smtpHost);
emailProperties.put("mail.smtp.port", Integer.valueOf(smtpPort));
try
{
this.messageDigest = MessageDigest.getInstance("SHA1");
}
catch (NoSuchAlgorithmException ex)
{
if (log.isErrorEnabled()) log.error("SHA1 algorithm not found", ex);
throw new InternalServerErrorException(ex);
}
xsltProc.registerExtensionFunction(new UUID());
xsltProc.registerExtensionFunction(new DecodeURI());
xsltProc.registerExtensionFunction(new com.atomgraph.linkeddatahub.writer.function.URLDecode());
xsltProc.registerExtensionFunction(new com.atomgraph.linkeddatahub.writer.function.Construct(xsltProc));
xsltProc.registerExtensionFunction(new com.atomgraph.linkeddatahub.writer.function.SendHTTPRequest(xsltProc, client));
Model mappingModel = locationMapper.toModel();
ResIterator prefixedMappings = mappingModel.listResourcesWithProperty(LocationMappingVocab.prefix);
try
{
while (prefixedMappings.hasNext())
{
Resource prefixMapping = prefixedMappings.next();
String prefix = prefixMapping.getRequiredProperty(LocationMappingVocab.prefix).getString();
// register mapped RDF documents in the XSLT processor so that document() returns them cached, throughout multiple transformations
TreeInfo doc = xsltProc.getUnderlyingConfiguration().buildDocumentTree(dataManager.resolve("", prefix));
xsltProc.getUnderlyingConfiguration().getGlobalDocumentPool().add(doc, prefix);
}
// register HTTPS URL of translations.rdf so it doesn't have to be requested repeatedly
try (InputStream translations = servletConfig.getServletContext().getResourceAsStream(XSLTWriterBase.TRANSLATIONS_PATH))
{
TreeInfo doc = xsltProc.getUnderlyingConfiguration().buildDocumentTree(new StreamSource(translations));
xsltProc.getUnderlyingConfiguration().getGlobalDocumentPool().add(doc, baseURI.resolve(XSLTWriterBase.TRANSLATIONS_PATH).toString());
}
}
catch (TransformerException ex)
{
if (log.isErrorEnabled()) log.error("Error reading mapped RDF document: {}", ex);
throw new IllegalStateException(ex);
}
finally
{
prefixedMappings.close();
}
xsltComp = xsltProc.newXsltCompiler();
xsltComp.setParameter(new QName("ldh", LDH.base.getNameSpace(), LDH.base.getLocalName()), new XdmAtomicValue(baseURI));
xsltComp.setURIResolver(new XsltResolver(LocationMapper.get(), new HashMap<>(), GraphStoreClient.create(client, mediaTypes), false, false, true)); // default Xerces parser does not support HTTPS
xsltExec = xsltComp.compile(stylesheet);
}
catch (FileNotFoundException ex)
{
if (log.isErrorEnabled()) log.error("File not found", ex);
throw new IllegalStateException(ex);
}
catch (IOException ex)
{
if (log.isErrorEnabled()) log.error("Could not load file", ex);
throw new IllegalStateException(ex);
}
catch (KeyStoreException ex)
{
if (log.isErrorEnabled()) log.error("Key store error", ex);
throw new IllegalStateException(ex);
}
catch (NoSuchAlgorithmException ex)
{
if (log.isErrorEnabled()) log.error("No such algorithm", ex);
throw new IllegalStateException(ex);
}
catch (CertificateException ex)
{
if (log.isErrorEnabled()) log.error("Certificate error", ex);
throw new IllegalStateException(ex);
}
catch (KeyManagementException | UnrecoverableKeyException ex)
{
if (log.isErrorEnabled()) log.error("Key management error", ex);
throw new IllegalStateException(ex);
}
catch (URISyntaxException ex)
{
if (log.isErrorEnabled()) log.error("URI syntax error", ex);
throw new IllegalStateException(ex);
}
catch (SaxonApiException ex)
{
if (log.isErrorEnabled()) log.error("System XSLT stylesheet error", ex);
throw new IllegalStateException(ex);
}
}
/**
* Post-construct initialization.
* Additional initialization (e.g. registering JAX-RS providers and factories) that cannot be cleanly done in the class constructor.
*/
@PostConstruct
public void init()
{
register(MultiPartFeature.class);
registerResourceClasses();
registerContainerRequestFilters();
registerContainerResponseFilters();
registerExceptionMappers();
registerClientFilters();
eventBus.register(this); // this system application will be receiving events about context changes
register(new ValidatingModelProvider(getMessageDigest()));
register(new ResultSetProvider());
register(new QueryProvider());
register(new QueryParamProvider());
register(new UpdateRequestProvider());
register(new ModelXSLTWriter(getXsltExecutable(), getOntModelSpec(), getDataManager(), getMessageDigest())); // writes (X)HTML responses
register(new ResultSetXSLTWriter(getXsltExecutable(), getOntModelSpec(), getDataManager(), getMessageDigest())); // writes (X)HTML responses
final com.atomgraph.linkeddatahub.Application system = this;
register(new AbstractBinder()
{
@Override
protected void configure()
{
bind(system).to(com.atomgraph.linkeddatahub.Application.class);
}
});
register(new AbstractBinder()
{
@Override
protected void configure()
{
bind(new com.atomgraph.client.MediaTypes()).to(com.atomgraph.client.MediaTypes.class).to(com.atomgraph.core.MediaTypes.class);
}
});
register(new AbstractBinder()
{
@Override
protected void configure()
{
bindFactory(AgentContextFactory.class).to(new TypeLiteral<Optional<AgentContext>>() {}).
in(RequestScoped.class);
}
});
register(new AbstractBinder()
{
@Override
protected void configure()
{
bindFactory(AuthorizationContextFactory.class).to(new TypeLiteral<Optional<AuthorizationContext>>() {}).
in(RequestScoped.class);
}
});
register(new AbstractBinder()
{
@Override
protected void configure()
{
bindFactory(ServiceFactory.class).to(new TypeLiteral<Optional<Service>>() {}).
in(RequestScoped.class);
}
});
register(new AbstractBinder()
{
@Override
protected void configure()
{
bindFactory(ApplicationFactory.class).to(new TypeLiteral<Optional<com.atomgraph.linkeddatahub.apps.model.Application>>() {}).
in(RequestScoped.class);
}
});