├── .gitignore ├── README.md ├── buildspec.yml ├── config └── logback.xml ├── pom.xml ├── profiles └── commonreleasetypes │ ├── 13 │ ├── AudioAlbumMusicAndSpeech.xsl │ ├── AudioAlbumMusicOnly.xsl │ ├── AudioBook.xsl │ ├── AudioSingle.xsl │ ├── BusinessProfile.xsl │ ├── DigitalBoxedSet.xsl │ ├── DigitalClassicalAudioAlbum.xsl │ ├── FilmBundle.xsl │ ├── LongformVideo.xsl │ ├── MidiRingtone.xsl │ ├── MixedMediaBundle.xsl │ ├── ReleaseProfileDeletedRules.xsl │ ├── Ringtone.xsl │ ├── SimpleVideoSingle.xsl │ ├── SingleResourceRelease.xsl │ ├── SingleResourceWithCoverArt.xsl │ ├── TVSeries.xsl │ ├── VideoAlbum.xsl │ ├── VideoSingle.xsl │ └── Wallpaper.xsl │ ├── 14 │ ├── AudioAlbum.xsl │ ├── AudioAlbumMusicOnly.xsl │ ├── AudioBook.xsl │ ├── AudioSingle.xsl │ ├── BusinessProfile.xsl │ ├── DigitalBoxedSet.xsl │ ├── DigitalClassicalAudioAlbum.xsl │ ├── FilmBundle.xsl │ ├── LongformVideo.xsl │ ├── MidiRingtone.xsl │ ├── MixedMediaBundle.xsl │ ├── Ringtone.xsl │ ├── SimpleVideoSingle.xsl │ ├── SingleResourceRelease.xsl │ ├── SingleResourceReleaseWithCoverArt.xsl │ ├── TVSeries.xsl │ ├── VideoAlbum.xsl │ └── VideoSingle.xsl │ └── 21 │ ├── Audio.xsl │ ├── BoxedSetVariant.xsl │ ├── ClassicalVariant.xsl │ ├── DjMix.xsl │ ├── LongFormMusicalWorkVideo.xsl │ ├── MixedMedia.xsl │ ├── ReleaseProfileTrackReleaseRules.xsl │ ├── Ringtone.xsl │ ├── SimpleAudioSingle.xsl │ ├── SimpleVideoSingle.xsl │ ├── Video.xsl │ └── release-notification-avs.sch.xsl ├── schema ├── ERN-2454 - MEAD XSD.zip ├── ddex.xsd ├── ddexC.xsd ├── ern │ ├── 41 │ │ ├── avs4.xsd │ │ └── release-notification.xsd │ ├── 341 │ │ ├── ddex.xsd │ │ ├── ddexC.xsd │ │ ├── iso3166a2.xsd │ │ ├── iso4217a.xsd │ │ ├── iso639a2.xsd │ │ └── release-notification.xsd │ ├── 371 │ │ ├── avs_20161006.xsd │ │ ├── ddex.xsd │ │ ├── ddexC.xsd │ │ ├── iso3166a2.xsd │ │ ├── iso4217a.xsd │ │ ├── iso639a2.xsd │ │ └── release-notification.xsd │ ├── 382 │ │ ├── avs_20161006.xsd │ │ ├── ddex.xsd │ │ ├── ddexC.xsd │ │ ├── iso3166a2.xsd │ │ ├── iso4217a.xsd │ │ ├── iso639a2.xsd │ │ └── release-notification.xsd │ ├── 383 │ │ ├── avs383.xsd │ │ └── release-notification.xsd │ └── 411 │ │ ├── avs411.xsd │ │ └── release-notification.xsd ├── iso3166a2.xsd ├── iso4217a.xsd ├── iso639a2.xsd ├── mead │ └── 10 │ │ ├── avs3.xsd │ │ └── media-enrichment-and-description.xsd ├── mlc │ ├── 14 │ │ ├── mlc-avs.xsd │ │ └── music-licensing-companies.xsd │ └── 131 │ │ ├── avs_20161219.xsd │ │ └── music-licensing-companies.xsd ├── release-notification.xsd ├── rin full │ └── 11 │ │ ├── avs4.xsd │ │ └── full-recording-information-notification.xsd └── rin │ └── 11 │ ├── avs4.xsd │ └── full-recording-information-notification.xsd └── src └── main ├── assembly └── bin.xml ├── java └── net │ └── ddex │ └── ern │ ├── config │ ├── AppConfig.java │ └── WebMvcConfig.java │ ├── controller │ └── ValidateController.java │ ├── exception │ ├── ErrorResponse.java │ ├── ExceptionControllerAdvice.java │ └── ValidatorException.java │ ├── initializer │ └── EmbeddedJetty.java │ ├── schema │ ├── Schema.java │ ├── SchemaFactory.java │ ├── SchemaValidator.java │ ├── ThreeFourOneSchema.java │ └── ThreeSevenOneSchema.java │ ├── service │ ├── SchemaService.java │ └── SchematronService.java │ ├── util │ └── SchemaBuilder.java │ └── vo │ ├── ValidationResponse.java │ └── ValidationResult.java ├── resources ├── application.properties └── logback.xml └── schematron ├── commonreleasetypes ├── 14 │ ├── NewReleaseMessage_BusinessProfile_14.sch │ ├── NewReleaseMessage_ReleaseProfile_AudioAlbumMusicOnly_14.sch │ ├── NewReleaseMessage_ReleaseProfile_AudioAlbum_14.sch │ ├── NewReleaseMessage_ReleaseProfile_AudioBook_14.sch │ ├── NewReleaseMessage_ReleaseProfile_AudioSingle_14.sch │ ├── NewReleaseMessage_ReleaseProfile_DigitalBoxedSet_14.sch │ ├── NewReleaseMessage_ReleaseProfile_DigitalClassicalAudioAlbum_14.sch │ ├── NewReleaseMessage_ReleaseProfile_FilmBundle_14.sch │ ├── NewReleaseMessage_ReleaseProfile_LongformVideo_14.sch │ ├── NewReleaseMessage_ReleaseProfile_MidiRingtone_14.sch │ ├── NewReleaseMessage_ReleaseProfile_MixedMediaBundle_14.sch │ ├── NewReleaseMessage_ReleaseProfile_Ringtone_14.sch │ ├── NewReleaseMessage_ReleaseProfile_SimpleVideoSingle_14.sch │ ├── NewReleaseMessage_ReleaseProfile_SingleResourceReleaseWithCoverArt_14.sch │ ├── NewReleaseMessage_ReleaseProfile_SingleResourceRelease_14.sch │ ├── NewReleaseMessage_ReleaseProfile_TVSeries_14.sch │ ├── NewReleaseMessage_ReleaseProfile_VideoAlbum_14.sch │ └── NewReleaseMessage_ReleaseProfile_VideoSingle_14.sch └── 21 │ ├── NewReleaseMessage_ReleaseProfile_Audio_21.sch │ ├── NewReleaseMessage_ReleaseProfile_BoxedSetVariant_21.sch │ ├── NewReleaseMessage_ReleaseProfile_ClassicalVariant_21.sch │ ├── NewReleaseMessage_ReleaseProfile_DjMix_21.sch │ ├── NewReleaseMessage_ReleaseProfile_LongFormMusicalWorkVideo_21.sch │ ├── NewReleaseMessage_ReleaseProfile_MixedMedia_21.sch │ ├── NewReleaseMessage_ReleaseProfile_ReleaseProfileTrackReleaseRules_21.sch │ ├── NewReleaseMessage_ReleaseProfile_Ringtone_21.sch │ ├── NewReleaseMessage_ReleaseProfile_SimpleAudioSingle_21.sch │ ├── NewReleaseMessage_ReleaseProfile_SimpleVideoSingle_21.sch │ ├── NewReleaseMessage_ReleaseProfile_Video_21.sch │ ├── avs.xml │ ├── release-notification-avs.sch │ └── release-notification.xsd ├── iso_abstract_expand.xsl ├── iso_dsdl_include.xsl ├── iso_schematron_skeleton_for_saxon.xsl └── iso_svrl_for_xslt2.xsl /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse ignore 2 | .settings/ 3 | .project 4 | .classpath 5 | # idea ignore 6 | .idea/ 7 | *.ipr 8 | *.iml 9 | *.iws 10 | <<<<<<< HEAD 11 | ======= 12 | /target/ 13 | *.gz 14 | *.log 15 | 130295703_20171205033227.xml 16 | >>>>>>> sme/rob-local 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

DDEX XML Validator

2 |

The DDEX Message Validator is an API that provides methods to validate DDEX XML based messages against 3 | the set of active schema versions and profile schematrons. 4 |

5 |

Development Requirements

6 | 11 |

Building

12 |

To build the source execute the following maven targets:

13 |
mvn clean install
14 |

After execution a file with the name ddex-message-validator-api-1.0-SNAPSHOT-bin.zip will appear in 'target/' directory. Unzip the file and and you will see three folders bin, etc, repo. Within the bin folder you will also see start-api.sh and start-api.bat. In your command line you can start the API by typing the following below.

15 |
start-api <port>
16 |

If a port is not specified the default port is 6060. The default profile has been set to "dev", this can be changed by setting spring.profiles.active environment variable.

17 |

In cases where you are using IntelliJ or Eclipse you can also run it from within your IDE locally.

18 |

Try the below URL in your browser to see if the service is running.

19 |
localhost:6060/api/status
20 | 21 |

Working with the code

22 |

If you don't have a personal IDE preference we recommend you use IntelliJ when working with the code. We use the maven assembly and 23 | appassembly plugin for wrapper script packaging support.

24 |

Technologies

25 | 32 |

The API uses Spring-WebMVC framework which provides a Model-View-Controller architecture. Having a MVC structure in our application allows for the input logic, business logic, and UI logic to be seperated but still have the flexible ability to loosely couple these elements together.

33 |

As an alternative to creating a stand-alone bundled WAR app we have incorporated Embedded Jetty as our application instantiator. By doing this you're able to instantiate Jetty within your Java program.

34 | 35 |

Ways to use API

36 | 40 |

You can use cURL command line tool to use the API to validate your XML documents.

41 |

Schema (XSD) example

42 |
curl -X POST -F 'messageSchemaVersionId=ern/341' -F 'messageFile=@location\xml\sme-album.xml' -F 'releaseProfileVersionId=commonreleasetypes/14/AudioAlbumMusicOnly' localhost:6060/api/json/validate
43 | 44 | -------------------------------------------------------------------------------- /buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | env: 4 | variables: 5 | JAVA_HOME: "/usr/lib/jvm/java-8-openjdk-amd64" 6 | 7 | phases: 8 | install: 9 | commands: 10 | - apt-get update -y 11 | - apt-get install -y maven 12 | pre_build: 13 | commands: 14 | - echo Nothing to do in the pre_build phase... 15 | build: 16 | commands: 17 | - echo Build started on `date` 18 | - mvn package 19 | post_build: 20 | commands: 21 | - echo Build completed on `date` 22 | artifacts: 23 | files: 24 | - target/messageUtil-1.0.jar 25 | discard-paths: yes -------------------------------------------------------------------------------- /config/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | net.ddex 7 | ddex-message-validator-api 8 | 1.0-SNAPSHOT 9 | 2008 10 | 11 | 12 | The Apache Software License, Version 2.0 13 | http://www.apache.org/licenses/LICENSE-2.0.txt 14 | repo 15 | 16 | 17 | 18 | 19 | 20 | org.codehaus.mojo 21 | appassembler-maven-plugin 22 | 1.10 23 | 24 | 25 | 26 | generate-daemons 27 | create-repository 28 | 29 | 30 | 31 | 32 | 33 | 34 | start-api 35 | net.ddex.ern.initializer.EmbeddedJetty 36 | 37 | booter-unix 38 | booter-windows 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-assembly-plugin 47 | 3.0.0 48 | 49 | 50 | package 51 | 52 | single 53 | 54 | 55 | 56 | 57 | 58 | src/main/assembly/bin.xml 59 | 60 | 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-compiler-plugin 65 | 3.1 66 | 67 | 1.8 68 | 1.8 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | org.codehaus.mojo.appassembler 79 | appassembler-booter 80 | 1.10 81 | 82 | 83 | 84 | 85 | org.springframework 86 | spring-webmvc 87 | 4.3.7.RELEASE 88 | 89 | 90 | 91 | org.eclipse.jetty 92 | jetty-servlets 93 | 9.4.19.v20190610 94 | 95 | 96 | 97 | org.eclipse.jetty 98 | jetty-server 99 | 9.4.19.v20190610 100 | 101 | 102 | 103 | commons-fileupload 104 | commons-fileupload 105 | 1.4 106 | 107 | 108 | 109 | org.eclipse.jetty 110 | jetty-http 111 | 9.4.19.v20190610 112 | 113 | 114 | 115 | 116 | org.eclipse.jetty 117 | jetty-util 118 | 9.4.19.v20190610 119 | 120 | 121 | 122 | 123 | org.eclipse.jetty 124 | jetty-io 125 | 9.4.19.v20190610 126 | 127 | 128 | 129 | ch.qos.logback 130 | logback-classic 131 | 1.1.7 132 | 133 | 134 | org.slf4j 135 | jcl-over-slf4j 136 | 1.7.21 137 | 138 | 139 | 140 | com.fasterxml.jackson.core 141 | jackson-core 142 | 2.11.0 143 | 144 | 145 | 146 | javax.servlet 147 | jstl 148 | 1.2 149 | 150 | 151 | 152 | com.fasterxml.jackson.core 153 | jackson-databind 154 | [2.9.9,) 155 | 156 | 157 | 158 | net.sf.saxon 159 | Saxon-HE 160 | 9.7.0-15 161 | 162 | 163 | 164 | junit 165 | junit 166 | 4.12 167 | test 168 | 169 | 170 | 171 | org.eclipse.jetty 172 | jetty-servlet 173 | 9.4.12.v20180830 174 | 175 | 176 | 177 | 178 | 179 | UTF-8 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /profiles/commonreleasetypes/14/MidiRingtone.xsl: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 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 | 52 | [] 53 | 54 | 55 | *[local-name()=' 56 | 57 | '] 58 | 60 | [] 61 | 62 | 63 | 64 | 65 | / 66 | 67 | @ 68 | 69 | 70 | @*[local-name()=' 71 | 72 | ' and namespace-uri()=' 73 | 74 | '] 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | / 84 | 85 | 86 | [ 87 | 88 | ] 89 | 90 | 91 | 92 | /@ 93 | 94 | 95 | 96 | 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 | U 139 | 140 | U 141 | 142 | 143 | 144 | U. 145 | 146 | n 147 | 148 | 149 | 150 | U. 151 | 152 | _ 153 | 154 | _ 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 165 | 166 |   167 |   168 |   169 | 170 | 171 | © 2006-2017 Digital Data Exchange, LLC (DDEX) 172 | This ISO Schematron file is, together with all DDEX standards, subject to two licences: If 173 | you wish to evaluate whether the standard meets your needs please have a look at the 174 | Evaluation Licence at https://kb.ddex.net/display/HBK/Evaluation+Licence+for+DDEX+Standards. 175 | If you want to implement and use this DDEX standard, please take out an Implementation 176 | Licence. For details please go to http://ddex.net/apply-ddex-implementation-licence. 177 | Failing a rule with a role of 'Fatal Error' means that the Conformance Tester must recommend 178 | to not award a Conformance Certificate or to retract a Conformance Certificate if one has 179 | already been issued. Failing a rule with a role of 'Conditional Fatal Error' is the same as a 180 | 'Fatal Error', however, the rule may be ignored if the Conformance Tester has no means of 181 | asserting whether the condition expressed in the rule has been met. 182 | Failing a rule a rule with a role of 'Error' means that the Conformance Tester must 183 | recommend to award a Partial Conformance Certificate or to downgrade a Conformance Certificate 184 | that has already been issued. However, if more than 1 rules (representing 50% of all rules 185 | with a role of 'Error' or 'Conditional Error') have been failed at least once, the Conformance 186 | Tester must recommend to not award a Conformance Certificate or to retract a Conformance 187 | Certificate if one has already been issued. Failing a rule with a role of 'Conditional Error' 188 | is the same as an 'Error', however, the rule may be ignored if the Conformance Tester has no 189 | means of asserting whether the condition expressed in the rule has been met. 190 | The following Clauses from the Release Profile standard are NOT checked by this ISO 191 | Schematron file: 3.3.1(1), 3.3.1(7)-(8), 3.4, 4.1, 4.2, 4.3(11), 4.3(14), 4.3(15a), 4.3(16b), 192 | 4.3(17), 4.3(19), 4.3(27)-(29), 4.3(37), 4.16(11)-(12), 4.7(11)-(12), 4.8(8), 4.8(9d), 193 | 4.8(10f), 4.8(11)-(12), 4.10(9) and similar clauses, 4.10(10) and similar clauses, 4.14(8) and 194 | 4.15(11). 195 | 196 | 197 | 198 | 199 | Ringtone_ReleaseProfileVersionId 200 | Ringtone_ReleaseProfileVersionId 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | MultiProfile_TrackReleaseMustNotContainManyResources 209 | MultiProfile_TrackReleaseMustNotContainManyResources 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | MidiRingtone_MustContainRingtoneComponentRelease 218 | MidiRingtone_MustContainRingtoneComponentRelease 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | MultiProfile_DisplayArtistMustBeProvided 227 | MultiProfile_DisplayArtistMustBeProvided 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | MultiProfile_DisplayArtistNamesMustBeDifferent 236 | MultiProfile_DisplayArtistNamesMustBeDifferent 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | MultiProfile_MainReleaseMustHaveGridOrICPN 245 | MultiProfile_MainReleaseMustHaveGridOrICPN 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | Ringtone_MustContainReleaseFromRelease 254 | Ringtone_MustContainReleaseFromRelease 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | MultiProfile_SoundRecordingMustNotHaveDeprecatedFlags 263 | MultiProfile_SoundRecordingMustNotHaveDeprecatedFlags 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | MultiProfile_LabelNameMustBeProvided2 272 | MultiProfile_LabelNameMustBeProvided2 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | Schematron Release Profile for Midi Ringtone (version 1.4) for the 281 | NewReleaseMessage. 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 296 | Fatal Error 297 | 298 | 299 | 300 | Fatal Error: #Midi Ringtone) The ReleaseProfileVersionId should be 301 | 'CommonReleaseTypes/14/Ringtone' (Release Profile 1.4, Clause 3.2, Rule 302 | 1364-1). 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 320 | 322 | 323 | 324 | 325 | 327 | Fatal Error 328 | 329 | 330 | 331 | Fatal Error: 332 | #Midi Ringtone) A Track Release must not contain more than one Resource (Release Profile 333 | 1.4, Clause 3.1, Rule 1365-1). 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 350 | 351 | 352 | 353 | 354 | 355 | 357 | Fatal Error 358 | 359 | 360 | 361 | Fatal Error: #Midi Ringtone) A Ringtone must contain one 362 | RingtoneRelease or RingbackToneRelease (Release Profile 1.4, Clause 3.1, Rule 363 | 1366-1). 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 381 | 383 | 384 | 385 | 386 | 387 | 388 | 390 | Fatal Error 391 | 392 | 393 | 394 | Fatal Error: 395 | #Midi Ringtone) At least one DisplayArtist shall be provided (Release Profile 1.4, 396 | Clause 4.3(12c)+4.3(15b), Rule 1367-1). 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 414 | 416 | 417 | 418 | 419 | 421 | Error 422 | 423 | 424 | 425 | Error: #Midi Ringtone) DisplayArtistNames for Release and Resource must be 426 | different (Release Profile 1.4, Clause 4.3(16a), Rule 1368-1). 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 443 | 444 | 445 | 446 | 447 | 448 | 450 | Fatal Error 451 | 452 | 453 | 454 | Fatal Error: #Midi Ringtone) The MainRelease shall be identified by 455 | either a GRid or by an ICPN (Release Profile 1.4, Clause 4.9(4), Rule 456 | 1369-1). 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 474 | 476 | 477 | 478 | 479 | 480 | 481 | 483 | Fatal Error 484 | 485 | 486 | 487 | Fatal Error: #Midi Ringtone) A Ringtone must contain a RelatedRelease 488 | of type IsReleaseFromRelease (Release Profile 1.4, Clause 4.9(9), Rule 489 | 1372-1). 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 507 | 509 | 510 | 511 | 512 | 513 | Information 514 | 515 | 516 | 517 | Information: #Midi Ringtone) No 518 | deprecated Flags (IsHiddenResource) must be provided for SoundRecordings (Release 519 | Profile 1.4, Clause 4.10(7h), Rule 1373-1). 520 | 521 | 522 | 523 | 524 | 525 | 526 | Information 527 | 528 | 529 | 530 | Information: #Midi Ringtone) No 531 | deprecated Flags (IsBonusResource) must be provided for SoundRecordings (Release Profile 532 | 1.4, Clause 4.10(7h), Rule 1373-2). 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 549 | 551 | 552 | 553 | 554 | 555 | 556 | 558 | Fatal Error 559 | 560 | 561 | 562 | Fatal Error: #Midi 563 | Ringtone) A LabelName has to be specified for each Release (Release Profile 1.4, 564 | Clause 4.13(8), Rule 1374-1). 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | -------------------------------------------------------------------------------- /profiles/commonreleasetypes/21/BoxedSetVariant.xsl: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 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 | [namespace-uri()=' 57 | 58 | '] 59 | 60 | 61 | 63 | [ 64 | 65 | ] 66 | 67 | 68 | 69 | / 70 | 71 | @ 72 | 73 | 74 | @*[local-name()=' 75 | 76 | ' and namespace-uri()=' 77 | 78 | '] 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | / 88 | 89 | 90 | [ 91 | 92 | ] 93 | 94 | 95 | 96 | /@ 97 | 98 | 99 | 100 | 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 | U 143 | 144 | U 145 | 146 | 147 | 148 | U. 149 | 150 | n 151 | 152 | 153 | 154 | U. 155 | 156 | _ 157 | 158 | _ 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 169 | 170 |   171 |   172 |   173 | 174 | 175 | © 2006-2018 Digital Data Exchange, LLC (DDEX) 176 | This ISO Schematron file is, together with all DDEX standards, subject to two licences: If you wish to evaluate whether the standard meets your needs please have a look at the Evaluation Licence at https://kb.ddex.net/display/HBK/Evaluation+Licence+for+DDEX+Standards. If you want to implement and use this DDEX standard, please take out an Implementation Licence. For details please go to http://ddex.net/apply-ddex-implementation-licence. 177 | Failing a rule with a role of 'Fatal Error' means that the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Fatal Error' is the same as a 'Fatal Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 178 | Failing a rule a rule with a role of 'Error' means that the Conformance Tester must recommend to award a Partial Conformance Certificate or to downgrade a Conformance Certificate that has already been issued. However, if more than 1 rules (representing 50% of all rules with a role of 'Error') have been failed at least once, the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Error' is the same as an 'Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 179 | The following Clauses from the Release Profile standard are NOT checked by this ISO Schematron file: 5.1.1 (partly), 5.3.1.1(1-3, 7.1, 7.3, 9), 5.3.1.2(2.1, 3-4, 5.1), 5.3.1.3(4-5), 5.3.1.4(3-5, 8), 5.3.3.1-2, 5.3.3.4, 5.4.1(4.1), 5.4.3(5), 5.4.4(3, 5), 5.5.1(2), 5.5.2(2.4, 3.5-3.7), 5.6(1, 3). This file also does not check any rules specified in the ERN Message Suite Standard (Version 4.1) specifications, sections 6.4 and 6.5, except for 6.4.8-10 180 | 181 | 182 | 183 | 184 | BoxedSet_ReleaseProfileVariantVersionId 185 | BoxedSet_ReleaseProfileVariantVersionId 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | BoxedSet_ResourceGroupType 194 | BoxedSet_ResourceGroupType 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | BoxedSet_MustContainResourceGroups 203 | BoxedSet_MustContainResourceGroups 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | BoxedSet_MustContainReleaseId 212 | BoxedSet_MustContainReleaseId 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | Schematron Release Profile for Boxed Set Variant (version 2.1) for the NewReleaseMessage. 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 235 | Fatal Error 236 | 237 | 238 | 239 | Fatal Error (Boxed Set Variant): The ReleaseProfileVariantVersionId should conform to clause 5.2.2 (Release Profile 2.1, Clause 5.2.2, Rule 1543-1). 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 257 | 259 | 260 | 261 | 262 | 263 | 264 | 266 | Fatal Error 267 | 268 | 269 | 270 | Fatal Error (Boxed Set Variant): For a Release of this type, second-level ResourceGroups shall have a ResourceGroupType of either Side, Component, ComponentRelease or ReleaseComponent (Release Profile 2.1, Clause 5.3.1.2(5.2), Rule 1544-1). 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 288 | 290 | 291 | 292 | 293 | 294 | 295 | 297 | Fatal Error 298 | 299 | 300 | 301 | Fatal Error (Boxed Set Variant): A Release of this type must contain at least two ResourceGroups of type ReleaseComponent (Release Profile 2.1, Clause 5.5.1(1), Rule 1545-1). 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 319 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | Fatal Error 328 | 329 | 330 | 331 | Fatal Error (Boxed Set Variant): The identifier of the 'component' Releases that make up the Boxed Set Release shall be placed into the ReleaseId composite of the relevant ResourceGroup (Release Profile 2.1, Clause 5.5.1(3), Rule 1546-1). 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 342 | Fatal Error 343 | 344 | 345 | 346 | Fatal Error (Boxed Set Variant): The identifier of the 'component' Releases that make up the Boxed Set Release shall be identified by either a GRid or an ICPN (Release Profile 2.1, Clause 5.5.1(3), Rule 1546-2). 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | -------------------------------------------------------------------------------- /profiles/commonreleasetypes/21/ReleaseProfileTrackReleaseRules.xsl: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 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 | [namespace-uri()=' 57 | 58 | '] 59 | 60 | 61 | 63 | [ 64 | 65 | ] 66 | 67 | 68 | 69 | / 70 | 71 | @ 72 | 73 | 74 | @*[local-name()=' 75 | 76 | ' and namespace-uri()=' 77 | 78 | '] 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | / 88 | 89 | 90 | [ 91 | 92 | ] 93 | 94 | 95 | 96 | /@ 97 | 98 | 99 | 100 | 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 | U 143 | 144 | U 145 | 146 | 147 | 148 | U. 149 | 150 | n 151 | 152 | 153 | 154 | U. 155 | 156 | _ 157 | 158 | _ 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 169 | 170 |   171 |   172 |   173 | 174 | 175 | © 2006-2018 Digital Data Exchange, LLC (DDEX) 176 | This ISO Schematron file is, together with all DDEX standards, subject to two licences: If you wish to evaluate whether the standard meets your needs please have a look at the Evaluation Licence at https://kb.ddex.net/display/HBK/Evaluation+Licence+for+DDEX+Standards. If you want to implement and use this DDEX standard, please take out an Implementation Licence. For details please go to http://ddex.net/apply-ddex-implementation-licence. 177 | Failing a rule with a role of 'Fatal Error' means that the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Fatal Error' is the same as a 'Fatal Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 178 | Failing a rule a rule with a role of 'Error' means that the Conformance Tester must recommend to award a Partial Conformance Certificate or to downgrade a Conformance Certificate that has already been issued. However, if more than 1 rules (representing 50% of all rules with a role of 'Error') have been failed at least once, the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Error' is the same as an 'Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 179 | 180 | 181 | 182 | 183 | MultiProfile_MustContainOneTrackReleasePerPrimaryResource 184 | MultiProfile_MustContainOneTrackReleasePerPrimaryResource 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | MultiProfile_TrackReleaseMustNotHaveISRC 193 | MultiProfile_TrackReleaseMustNotHaveISRC 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | MultiProfile_TrackReleaseMustHaveOnePrimaryResource 202 | MultiProfile_TrackReleaseMustHaveOnePrimaryResource 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | MultiProfile_TrackReleaseMustNotHaveSecondaryResources 211 | MultiProfile_TrackReleaseMustNotHaveSecondaryResources 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | MultiProfile_TrackReleaseMustNotHaveRedundantTitles 220 | MultiProfile_TrackReleaseMustNotHaveRedundantTitles 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | Schematron Release Profile for Release Profile Track Release Rules (version 2.1) for the NewReleaseMessage. 229 | 230 | 231 | 232 | 233 | 234 | 237 | 239 | 240 | 241 | 242 | 243 | 244 | 246 | Fatal Error 247 | 248 | 249 | 250 | Fatal Error (Release Profile Track Release Rules): A Release of this type must contain exactly one TrackRelease for each Primary Resource referenced in the Main Release (Release Profile 2.1, Clause 5.1.1(b), Rule 1538-1). 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 268 | 270 | 271 | 272 | 273 | 274 | Fatal Error 275 | 276 | 277 | 278 | Fatal Error (Release Profile Track Release Rules): An ISRC as an identifier for a TrackRelease shall be communicated as a ProprietaryId (Release Profile 2.1, Clause 5.3.1.3(3), Rule 1539-1). 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 295 | 297 | 298 | 299 | 300 | 301 | 302 | 304 | Fatal Error 305 | 306 | 307 | 308 | Fatal Error (Release Profile Track Release Rules): A TrackRelease must refer to one Primary Resource (Release Profile 2.1, Clause 5.6(2a), Rule 1540-1). 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 326 | 328 | 329 | 330 | 331 | 333 | Fatal Error 334 | 335 | 336 | 337 | Fatal Error (Release Profile Track Release Rules): A TrackRelease must not refer to a Secondary Resource (Release Profile 2.1, Clause 5.6(2b), Rule 1541-1). 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 354 | 356 | 357 | 358 | 359 | 361 | Error 362 | 363 | 364 | 365 | Error (Release Profile Track Release Rules): Title information for TrackReleases shall only be provided if it differs from the title information provided on the Resource (Release Profile 2.1, Clause 5.6(4), Rule 1542-1). 366 | 367 | 368 | 369 | 370 | 371 | 373 | Error 374 | 375 | 376 | 377 | Error (Release Profile Track Release Rules): Title information for TrackReleases shall only be provided if it differs from the title information provided on the Resource (Release Profile 2.1, Clause 5.6(4), Rule 1542-2). 378 | 379 | 380 | 381 | 382 | 383 | 385 | Error 386 | 387 | 388 | 389 | Error (Release Profile Track Release Rules): Title information for TrackReleases shall only be provided if it differs from the title information provided on the Resource (Release Profile 2.1, Clause 5.6(4), Rule 1542-3). 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | -------------------------------------------------------------------------------- /schema/ERN-2454 - MEAD XSD.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ddexnet/ern-validator-api/9dcc5078f30826548832ba20bd377b535bfef8c1/schema/ERN-2454 - MEAD XSD.zip -------------------------------------------------------------------------------- /src/main/assembly/bin.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | bin 8 | 9 | zip 10 | 11 | 12 | 13 | ${project.basedir} 14 | 15 | 16 | ${project.basedir}/xml/** 17 | 18 | 19 | ${project.basedir}/.classpath 20 | 21 | 22 | ${project.basedir}/.settings/** 23 | 24 | 25 | ${project.basedir}/.project 26 | 27 | 28 | ${project.basedir}/application.log* 29 | 30 | 31 | ${project.basedir}/src/** 32 | 33 | 34 | ${project.basedir}/target/** 35 | 36 | 37 | ${project.basedir}/pom.xml 38 | 39 | 40 | ${project.basedir}/jetty_tutorial.iml 41 | 42 | 43 | ${project.basedir}/.idea/** 44 | 45 | 46 | bin 47 | 48 | 49 | target/appassembler/repo 50 | repo 51 | 52 | maven-metadata-appassembler.xml 53 | 54 | 55 | 56 | target/generated-resources/appassembler/booter-unix/etc 57 | etc 58 | 59 | start-api.xml 60 | 61 | 62 | 63 | target/generated-resources/appassembler/booter-unix/bin 64 | bin 65 | 0755 66 | unix 67 | 68 | 69 | target/generated-resources/appassembler/booter-windows/bin 70 | bin 71 | 0755 72 | dos 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.ComponentScan; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.PropertySource; 7 | import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; 8 | 9 | @Configuration 10 | @ComponentScan(basePackages = "net.ddex.ern") 11 | @PropertySource("classpath:application.properties") 12 | public class AppConfig { 13 | 14 | @Bean 15 | public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { 16 | return new PropertySourcesPlaceholderConfigurer(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/config/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.multipart.commons.CommonsMultipartResolver; 6 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 8 | 9 | @Configuration 10 | @EnableWebMvc 11 | public class WebMvcConfig extends WebMvcConfigurerAdapter { 12 | 13 | @Bean 14 | public CommonsMultipartResolver multipartResolver() { 15 | CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); 16 | multipartResolver.setDefaultEncoding("UTF-8"); 17 | multipartResolver.setMaxUploadSize(-1); 18 | return multipartResolver; 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/controller/ValidateController.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.controller; 2 | 3 | import java.io.IOException; 4 | import java.util.AbstractMap; 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Optional; 10 | 11 | import javax.xml.parsers.ParserConfigurationException; 12 | import javax.xml.stream.XMLStreamException; 13 | import javax.xml.transform.TransformerException; 14 | import javax.xml.xpath.XPathExpressionException; 15 | 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.beans.factory.annotation.Value; 20 | import org.springframework.web.bind.annotation.ExceptionHandler; 21 | import org.springframework.web.bind.annotation.GetMapping; 22 | import org.springframework.web.bind.annotation.PostMapping; 23 | import org.springframework.web.bind.annotation.RequestParam; 24 | import org.springframework.web.bind.annotation.RestController; 25 | import org.springframework.web.multipart.MultipartFile; 26 | import org.xml.sax.SAXException; 27 | 28 | import net.ddex.ern.exception.ValidatorException; 29 | import net.ddex.ern.service.SchemaService; 30 | import net.ddex.ern.service.SchematronService; 31 | import net.ddex.ern.vo.ValidationResponse; 32 | 33 | @RestController 34 | public class ValidateController { 35 | 36 | private static final Logger LOGGER = LoggerFactory.getLogger(ValidateController.class); 37 | private static String PROFILE_ROOT = "profiles/commonreleasetypes/"; 38 | 39 | @Autowired 40 | private SchemaService schemaService; 41 | 42 | @Autowired 43 | private SchematronService schematronService; 44 | 45 | @Value("${max.input.file.size.kb}") 46 | private Long maxInputFileSizeinKb; 47 | 48 | @Value("#{${releaseProfileVersion.map.schema}}") 49 | private Map releaseProfileVersionMap; 50 | 51 | @GetMapping(path = "/status", produces = "text/plain") 52 | public String test() { 53 | return "The service is running"; 54 | } 55 | 56 | @PostMapping(path = "/json/validate", produces = "application/json") 57 | public List> validate(@RequestParam(value = "messageFile") MultipartFile file, 58 | @RequestParam(value = "messageSchemaVersionId") Optional schemaVersion, 59 | @RequestParam(value = "releaseProfileVersionId") Optional releaseProfile, 60 | @RequestParam(value = "businessProfileValidationRequired", required = false, defaultValue = "false") boolean businessProfileValidationRequired) 61 | throws IOException, XMLStreamException, TransformerException, SAXException, XPathExpressionException, 62 | ValidatorException, ParserConfigurationException { 63 | 64 | LOGGER.info("file size is : {}", file.getSize() / 1000); 65 | if (file.getSize() / 1000 > maxInputFileSizeinKb) { 66 | throw new ValidatorException("MAX_FILE_SIZE_LIMIT_FAILED", 67 | "Input File Size cannot be greater than 15000 KB"); 68 | } 69 | List> list = new ArrayList<>(2); 70 | Map map = new HashMap<>(2); 71 | 72 | String _schemaVersion = schemaVersion.isPresent() ? schemaVersion.get().replace(".", "") : ""; 73 | _schemaVersion = _schemaVersion.startsWith("/") ? _schemaVersion.substring(1) : _schemaVersion; 74 | _schemaVersion = _schemaVersion.endsWith("/") ? _schemaVersion.substring(0, _schemaVersion.length() - 1) 75 | : _schemaVersion; 76 | 77 | String _releaseProfile = releaseProfile.isPresent() ? releaseProfile.get().replace(".", "") : "none"; 78 | _releaseProfile = _releaseProfile.startsWith("/") ? _releaseProfile.substring(1) : _releaseProfile; 79 | _releaseProfile = _releaseProfile.endsWith("/") ? _releaseProfile.substring(0, _releaseProfile.length() - 1) 80 | : _releaseProfile; 81 | 82 | String releaseProfileVersion = releaseProfileVersionMap.get(_schemaVersion.replace("/", "")) != null ? releaseProfileVersionMap.get(_schemaVersion.replace("/", "")).concat("/") : "none"; 83 | LOGGER.info("releaseProfileVersion is : {}", releaseProfileVersion); 84 | String releaseProfileXslPath = null; 85 | try { 86 | AbstractMap.SimpleEntry spec = schemaService.validateSchema(file.getInputStream(), 87 | _schemaVersion, _releaseProfile); 88 | map.put("schema", "Message validates against schema version " + spec.getKey()); 89 | _schemaVersion = _schemaVersion.isEmpty() ? spec.getKey() : _schemaVersion; 90 | releaseProfileXslPath = _releaseProfile.isEmpty() ? String.format("%s%s", spec.getValue(), ".xsl") 91 | : String.format("%s%s%s%s", PROFILE_ROOT, releaseProfileVersion, _releaseProfile, ".xsl"); 92 | } catch (SAXException e) { 93 | LOGGER.error(e.getMessage()); 94 | map.put("schema", e.getMessage()); 95 | list.add(map); 96 | return list; 97 | } 98 | if (!(_releaseProfile.equalsIgnoreCase("none") || _schemaVersion.equalsIgnoreCase("341"))) { 99 | map.put("schematron", 100 | schematronService.schematron2Map(file.getInputStream(), releaseProfileXslPath, _schemaVersion)); 101 | } 102 | if (businessProfileValidationRequired) { 103 | map.put("businessProfileSchematron", schematronService.schematron2Map(file.getInputStream(), 104 | String.format("%s%s%s%s", PROFILE_ROOT, releaseProfileVersion, "BusinessProfile", ".xsl"), _schemaVersion)); 105 | } 106 | list.add(map); 107 | return list; 108 | } 109 | 110 | @ExceptionHandler 111 | public ValidationResponse handleValidatorException(ValidatorException ex) { 112 | LOGGER.error(ex.getMessage()); 113 | return new ValidationResponse(ex.getStatus(), ex.getErrorMessage()); 114 | } 115 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/exception/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.exception; 2 | 3 | /** 4 | * Created by eli on 8/7/2017. 5 | */ 6 | public class ErrorResponse { 7 | private int errorCode; 8 | private String message; 9 | 10 | public int getErrorCode() { 11 | return errorCode; 12 | } 13 | 14 | public void setErrorCode(int errorCode) { 15 | this.errorCode = errorCode; 16 | } 17 | 18 | public String getMessage() { 19 | return message; 20 | } 21 | 22 | public void setMessage(String message) { 23 | this.message = message; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/exception/ExceptionControllerAdvice.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.exception; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | 10 | /** 11 | * Created by eli on 8/7/2017. 12 | */ 13 | @ControllerAdvice 14 | public class ExceptionControllerAdvice { 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionControllerAdvice.class); 17 | 18 | @ExceptionHandler(ValidatorException.class) 19 | public ResponseEntity exceptionHandler(ValidatorException ex) { 20 | ErrorResponse error = new ErrorResponse(); 21 | error.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); 22 | System.out.println("##############################"); 23 | error.setMessage(ex.getErrorMessage()); 24 | LOGGER.error("An error occured while processing request. {}", ex.getMessage()); 25 | return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/exception/ValidatorException.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.bind.annotation.ResponseStatus; 5 | 6 | @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Validator configuration error") 7 | public class ValidatorException extends Exception { 8 | 9 | private static final long serialVersionUID = 1L; 10 | private String status; 11 | private String errorMessage; 12 | 13 | public ValidatorException() { 14 | super(); 15 | } 16 | 17 | public ValidatorException(String errorMessage) { 18 | super(errorMessage); 19 | this.errorMessage = errorMessage; 20 | } 21 | 22 | public ValidatorException(String status, String errorMessage) { 23 | super(errorMessage); 24 | this.status = status; 25 | this.errorMessage = errorMessage; 26 | } 27 | 28 | public ValidatorException(String errorMessage, Throwable throwable) { 29 | super(throwable); 30 | this.errorMessage = errorMessage; 31 | } 32 | 33 | public String getErrorMessage() { 34 | return errorMessage; 35 | } 36 | 37 | public String getStatus() { 38 | return status; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/initializer/EmbeddedJetty.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.initializer; 2 | 3 | import java.io.IOException; 4 | 5 | import org.eclipse.jetty.server.Server; 6 | import org.eclipse.jetty.servlet.FilterHolder; 7 | import org.eclipse.jetty.servlet.FilterMapping; 8 | import org.eclipse.jetty.servlet.ServletContextHandler; 9 | import org.eclipse.jetty.servlet.ServletHolder; 10 | import org.eclipse.jetty.servlets.CrossOriginFilter; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.web.context.ContextLoaderListener; 14 | import org.springframework.web.context.WebApplicationContext; 15 | import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; 16 | import org.springframework.web.servlet.DispatcherServlet; 17 | 18 | public class EmbeddedJetty { 19 | 20 | private static final Logger LOGGER = LoggerFactory.getLogger(EmbeddedJetty.class); 21 | private static final int DEFAULT_PORT = 6060; 22 | private static final String CONTEXT_PATH = "/"; 23 | private static final String CONFIG_LOCATION = "net/ddex/ern/config"; 24 | private static final String MAPPING_URL = "/api/*"; 25 | private static final String DEFAULT_PROFILE = "dev"; 26 | private static org.springframework.web.context.WebApplicationContext WebApplicationContext; 27 | 28 | public static void main(String[] args) throws Exception { 29 | new EmbeddedJetty().startJetty(getPortFromArgs(args)); 30 | } 31 | 32 | private static int getPortFromArgs(String[] args) { 33 | if (args.length > 0) { 34 | try { 35 | return Integer.valueOf(args[0]); 36 | } catch (NumberFormatException ignore) {} 37 | } 38 | LOGGER.debug("No server port configured, falling back to {}", DEFAULT_PORT); 39 | return DEFAULT_PORT; 40 | } 41 | 42 | private void startJetty(int port) throws Exception { 43 | LOGGER.debug("Starting server at port {}", port); 44 | Server server = new Server(port); 45 | ServletContextHandler myHand = getServletContextHandler(getContext()); 46 | setAccessControlAllowOrigin(myHand); 47 | server.setHandler(myHand); 48 | server.start(); 49 | LOGGER.info("Server started at port {}", port); 50 | server.join(); 51 | } 52 | 53 | private static ServletContextHandler getServletContextHandler(WebApplicationContext context) throws IOException { 54 | 55 | ServletContextHandler contextHandler = new ServletContextHandler(); 56 | contextHandler.setContextPath(CONTEXT_PATH); 57 | contextHandler.setWelcomeFiles(new String[]{ "index.html" }); 58 | contextHandler.setErrorHandler(null); 59 | contextHandler.addServlet(new ServletHolder(new DispatcherServlet(context)), MAPPING_URL); 60 | contextHandler.addEventListener(new ContextLoaderListener(context)); 61 | 62 | return contextHandler; 63 | 64 | } 65 | 66 | private static void setAccessControlAllowOrigin(ServletContextHandler context) { 67 | FilterHolder holder = new FilterHolder(CrossOriginFilter.class); 68 | holder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*"); 69 | holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "http://localhost:8000/"); 70 | holder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,PUT,HEAD"); 71 | holder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin"); 72 | holder.setName("cross-origin"); 73 | FilterMapping fm = new FilterMapping(); 74 | fm.setFilterName("cross-origin"); 75 | fm.setPathSpec("*"); 76 | context.getServletHandler().addFilter(holder, fm); 77 | } 78 | 79 | private static WebApplicationContext getContext() { 80 | AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); 81 | context.setConfigLocation(CONFIG_LOCATION); 82 | context.getEnvironment().setDefaultProfiles(DEFAULT_PROFILE); 83 | return context; 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/schema/Schema.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.schema; 2 | 3 | import net.ddex.ern.exception.ValidatorException; 4 | import org.w3c.dom.Document; 5 | import org.xml.sax.SAXException; 6 | 7 | import javax.xml.transform.Result; 8 | import javax.xml.validation.Validator; 9 | 10 | /** 11 | * Created by rdewilde on 5/13/2017. 12 | */ 13 | public interface Schema { 14 | Validator getValidator(); 15 | 16 | String validate(Document ern, Result result) throws SAXException, ValidatorException; 17 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/schema/SchemaFactory.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.schema; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | /** 7 | * Created by rdewilde on 5/13/2017. 8 | */ 9 | public class SchemaFactory { 10 | 11 | private static final Logger logger = LoggerFactory.getLogger(SchemaFactory.class); 12 | 13 | public Schema getSchema() { 14 | return new ThreeFourOneSchema(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/schema/SchemaValidator.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.schema; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.xml.transform.Result; 6 | import javax.xml.transform.dom.DOMSource; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | import org.w3c.dom.Document; 13 | import org.xml.sax.SAXException; 14 | 15 | import net.ddex.ern.exception.ValidatorException; 16 | import net.ddex.ern.util.SchemaBuilder; 17 | 18 | @Component 19 | public class SchemaValidator { 20 | 21 | private static final Logger LOGGER = LoggerFactory.getLogger(SchemaValidator.class); 22 | private javax.xml.validation.Schema schema; 23 | 24 | @Autowired 25 | private SchemaBuilder schemaBuilder; 26 | 27 | public void validate(String schemaVersion, String profile, Document ern, Result result) 28 | throws SAXException, ValidatorException { 29 | DOMSource source = new DOMSource(ern); 30 | try { 31 | schema = schemaBuilder.getSchema(schemaVersion); 32 | schema.newValidator().validate(source, result); 33 | } catch (IOException e) { 34 | LOGGER.error("IOException while validating schema.", e); 35 | throw new ValidatorException(e.getMessage(), e); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/schema/ThreeFourOneSchema.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.schema; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import javax.xml.XMLConstants; 7 | import javax.xml.transform.Result; 8 | import javax.xml.transform.Source; 9 | import javax.xml.transform.dom.DOMSource; 10 | import javax.xml.transform.stream.StreamSource; 11 | import javax.xml.validation.SchemaFactory; 12 | import javax.xml.validation.Validator; 13 | 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.w3c.dom.Document; 17 | import org.xml.sax.SAXException; 18 | 19 | import net.ddex.ern.exception.ValidatorException; 20 | 21 | /** 22 | * Electronic Release Notification 3.4.1 23 | */ 24 | public class ThreeFourOneSchema implements Schema { 25 | 26 | private static final Logger logger = LoggerFactory.getLogger(ThreeFourOneSchema.class); 27 | private static javax.xml.validation.Schema schema; 28 | 29 | static { 30 | Source[] schemaFiles = new Source[]{ 31 | new StreamSource(new File("schema/release-notification.xsd")), 32 | new StreamSource(new File("schema/ddexC.xsd")), 33 | new StreamSource(new File("schema/ddex.xsd")), 34 | new StreamSource(new File("schema/iso3166a2.xsd")), 35 | new StreamSource(new File("schema/iso4217a.xsd")), 36 | new StreamSource(new File("schema/iso639a2.xsd")) 37 | }; 38 | 39 | SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 40 | try { 41 | factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); 42 | factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); 43 | schema = factory.newSchema(schemaFiles); 44 | } catch (SAXException e) { 45 | e.printStackTrace(); 46 | // TODO: Catch this on startup earlier 47 | System.exit(2); 48 | } 49 | } 50 | 51 | @Override 52 | public Validator getValidator() { 53 | return schema.newValidator(); 54 | } 55 | 56 | @Override 57 | public String validate(Document ern, Result result) throws ValidatorException { 58 | DOMSource source = new DOMSource(ern); 59 | String valid = "Document is valid"; 60 | try { 61 | getValidator().validate(source); 62 | } catch (IOException e) { 63 | // logger.error(e.getMessage()); 64 | throw new ValidatorException(e.getMessage(), e); 65 | } catch (SAXException e) { 66 | // logger.error(e.getMessage()); 67 | throw new ValidatorException(e.getMessage(), e); 68 | } 69 | return valid; 70 | 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/schema/ThreeSevenOneSchema.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.schema; 2 | 3 | import net.ddex.ern.exception.ValidatorException; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.w3c.dom.Document; 7 | import org.xml.sax.SAXException; 8 | 9 | import javax.xml.XMLConstants; 10 | import javax.xml.transform.Result; 11 | import javax.xml.transform.Source; 12 | import javax.xml.transform.dom.DOMSource; 13 | import javax.xml.transform.stream.StreamSource; 14 | import javax.xml.validation.SchemaFactory; 15 | import javax.xml.validation.Validator; 16 | import java.io.File; 17 | import java.io.IOException; 18 | 19 | /** 20 | * Electronic Release Notification 3.4.1 21 | */ 22 | public class ThreeSevenOneSchema implements Schema { 23 | 24 | private static final Logger logger = LoggerFactory.getLogger(ThreeFourOneSchema.class); 25 | private static javax.xml.validation.Schema schema; 26 | 27 | static { 28 | Source[] schemaFiles = new Source[]{ 29 | new StreamSource(new File("schema/release-notification.xsd")), 30 | new StreamSource(new File("schema/ddexC.xsd")), 31 | new StreamSource(new File("schema/ddex.xsd")), 32 | new StreamSource(new File("schema/iso3166a2.xsd")), 33 | new StreamSource(new File("schema/iso4217a.xsd")), 34 | new StreamSource(new File("schema/iso639a2.xsd")) 35 | }; 36 | 37 | SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 38 | try { 39 | factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); 40 | factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); 41 | schema = factory.newSchema(schemaFiles); 42 | } catch (SAXException e) { 43 | e.printStackTrace(); 44 | // TODO: Catch this on startup earlier 45 | System.exit(2); 46 | } 47 | } 48 | 49 | @Override 50 | public Validator getValidator() { 51 | return schema.newValidator(); 52 | } 53 | 54 | @Override 55 | public String validate(Document ern, Result result) throws ValidatorException { 56 | DOMSource source = new DOMSource(ern); 57 | String valid = "Document is valid"; 58 | try { 59 | getValidator().validate(source); 60 | } catch (IOException e) { 61 | // logger.error(e.getMessage()); 62 | throw new ValidatorException(e.getMessage(), e); 63 | } catch (SAXException e) { 64 | // logger.error(e.getMessage()); 65 | throw new ValidatorException(e.getMessage(), e); 66 | } 67 | return valid; 68 | 69 | } 70 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/service/SchemaService.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.service; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.AbstractMap; 6 | 7 | import javax.xml.XMLConstants; 8 | import javax.xml.parsers.DocumentBuilder; 9 | import javax.xml.parsers.DocumentBuilderFactory; 10 | import javax.xml.parsers.ParserConfigurationException; 11 | import javax.xml.xpath.XPath; 12 | import javax.xml.xpath.XPathConstants; 13 | import javax.xml.xpath.XPathExpressionException; 14 | import javax.xml.xpath.XPathFactory; 15 | 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.stereotype.Service; 20 | import org.w3c.dom.Document; 21 | import org.w3c.dom.Element; 22 | import org.w3c.dom.Node; 23 | import org.w3c.dom.NodeList; 24 | import org.xml.sax.SAXException; 25 | 26 | import net.ddex.ern.exception.ValidatorException; 27 | import net.ddex.ern.schema.SchemaValidator; 28 | 29 | /** 30 | * Created by rdewilder on 4/16/2017. 31 | */ 32 | 33 | @Service("schemaService") 34 | public class SchemaService { 35 | 36 | private static final Logger LOGGER = LoggerFactory.getLogger(SchemaService.class); 37 | 38 | private static final String XPATH_EXPRESSION = "/*"; 39 | 40 | @Autowired 41 | private SchemaValidator schemaValidator; 42 | 43 | // Todo: https://stackoverflow.com/questions/15732/whats-the-best-way-to-validate-an-xml-file-against-an-xsd-file 44 | // use SAX instead of Dom 45 | public AbstractMap.SimpleEntry validateSchema(InputStream is, String schemaVersion, String profile) 46 | throws SAXException, ValidatorException, ParserConfigurationException { 47 | 48 | // DocumentBuilderFactory and DocumentBuilder are not thread safe 49 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 50 | dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); 51 | dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); 52 | dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); 53 | dbf.setNamespaceAware(true); 54 | Document doc; 55 | 56 | // Try to create the DOM from the uploaded file 57 | try { 58 | DocumentBuilder parser = dbf.newDocumentBuilder(); 59 | doc = parser.parse(is); 60 | } catch (ParserConfigurationException e) { 61 | LOGGER.error(e.getMessage()); 62 | throw new ValidatorException("Could not create XML parser", e); 63 | } catch (IOException e) { 64 | LOGGER.error(e.getMessage()); 65 | throw new ValidatorException("IOException during XML parse", e); 66 | } 67 | 68 | // Extract the Schema and profile from XML if not in request 69 | if (schemaVersion.isEmpty() || profile.isEmpty()) { 70 | AbstractMap.SimpleEntry schemaProfile = exractProfileAndSchemaVersion(doc); 71 | 72 | if (schemaVersion.isEmpty() && !"".equals(schemaProfile.getKey())) 73 | schemaVersion = schemaProfile.getKey(); 74 | else if (schemaVersion.isEmpty()) { 75 | LOGGER.error("Schema Version not found in request or XML."); 76 | throw new ValidatorException("MANDATORY_PARAMS_NOT_FOUND", 77 | "Error occurred while validating XML. Message Schema Version not found in request or XML."); 78 | } 79 | 80 | if (profile.isEmpty() && !"".equals(schemaProfile.getValue())) 81 | profile = schemaProfile.getValue(); 82 | else if (profile.isEmpty()) { 83 | LOGGER.error("Profile not found in request or XML."); 84 | throw new ValidatorException("MANDATORY_PARAMS_NOT_FOUND", 85 | "Error occurred while validating XML. Release Profile Version not found in request or XML."); 86 | } 87 | } 88 | LOGGER.info("schemaVersion: {}, profile: {}", schemaVersion, profile); 89 | schemaValidator.validate(schemaVersion, profile, doc, null); 90 | return new AbstractMap.SimpleEntry<>(schemaVersion, profile); 91 | } 92 | 93 | // Todo: use SAX instead of DOM 94 | private AbstractMap.SimpleEntry exractProfileAndSchemaVersion(Document doc) 95 | throws ValidatorException { 96 | XPath xPath = XPathFactory.newInstance().newXPath(); 97 | String schemaVersion = ""; 98 | String profile = ""; 99 | try { 100 | NodeList nodeList = (NodeList) xPath.compile(SchemaService.XPATH_EXPRESSION).evaluate(doc, XPathConstants.NODESET); 101 | for (int i = 0; i < nodeList.getLength(); i++) { 102 | Node nNode = nodeList.item(i); 103 | if (nNode.getNodeType() == Node.ELEMENT_NODE) { 104 | Element eElement = (Element) nNode; 105 | if (!"".equals(eElement.getAttribute("MessageSchemaVersionId"))) { 106 | schemaVersion = eElement.getAttribute("MessageSchemaVersionId"); 107 | schemaVersion = schemaVersion.startsWith("/") ? schemaVersion.substring(1) : schemaVersion; 108 | } 109 | if (!"".equals(eElement.getAttribute("ReleaseProfileVersionId "))) { 110 | profile = eElement.getAttribute("ReleaseProfileVersionId "); 111 | profile = profile.startsWith("/") ? profile.substring(1) : profile; 112 | } 113 | } 114 | } 115 | } catch (XPathExpressionException e) { 116 | LOGGER.error(e.getMessage()); 117 | throw new ValidatorException("XPath error during schema version extraction", e); 118 | } 119 | 120 | return new AbstractMap.SimpleEntry<>(schemaVersion, profile); 121 | } 122 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/service/SchematronService.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.service; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | import javax.xml.XMLConstants; 12 | import javax.xml.namespace.NamespaceContext; 13 | import javax.xml.stream.XMLStreamException; 14 | import javax.xml.transform.Transformer; 15 | import javax.xml.transform.TransformerException; 16 | import javax.xml.transform.TransformerFactory; 17 | import javax.xml.transform.dom.DOMResult; 18 | import javax.xml.transform.sax.SAXSource; 19 | import javax.xml.transform.sax.SAXTransformerFactory; 20 | import javax.xml.transform.stream.StreamSource; 21 | import javax.xml.xpath.XPath; 22 | import javax.xml.xpath.XPathConstants; 23 | import javax.xml.xpath.XPathExpression; 24 | import javax.xml.xpath.XPathExpressionException; 25 | import javax.xml.xpath.XPathFactory; 26 | 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | import org.springframework.stereotype.Service; 30 | import org.w3c.dom.NodeList; 31 | import org.xml.sax.InputSource; 32 | 33 | import net.ddex.ern.exception.ValidatorException; 34 | 35 | /** 36 | * Created by rdewilde on 4/16/2017. 37 | */ 38 | 39 | @Service("schematronService") 40 | public class SchematronService { 41 | 42 | // private SAXTransformerFactory stf = new net.sf.saxon.TransformerFactoryImpl(); 43 | private static final Logger LOGGER = LoggerFactory.getLogger(SchematronService.class); 44 | 45 | public List> schematron2Map(InputStream is, String profileVersion, String schemaVersion) 46 | throws XMLStreamException, IOException, TransformerException, XPathExpressionException, ValidatorException { 47 | 48 | SAXSource saxSource = new SAXSource(new InputSource(is)); 49 | DOMResult result = new DOMResult(); 50 | // SAXTransformerFactory stf = new net.sf.saxon.TransformerFactoryImpl(); 51 | try { 52 | TransformerFactory sf = SAXTransformerFactory.newInstance(); 53 | sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); 54 | sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); 55 | Transformer transformer = sf.newTransformer(new StreamSource(profileVersion)); 56 | transformer.transform(saxSource, result); 57 | } catch (TransformerException ex) { 58 | LOGGER.error("Exception: {}", ex.getMessage()); 59 | String releaseProfile = profileVersion.substring(profileVersion.lastIndexOf("/") + 1, 60 | profileVersion.lastIndexOf(".")); 61 | throw new ValidatorException( 62 | String.format("%s%s%s%s", "Error while validating Schematron. Release profile ", releaseProfile, 63 | " does not exist for schema version ", schemaVersion), 64 | ex); 65 | } 66 | XPathFactory xPathfactory = XPathFactory.newInstance(); 67 | XPath xpath = xPathfactory.newXPath(); 68 | 69 | xpath.setNamespaceContext(getNamespaceContext()); 70 | 71 | XPathExpression expr = xpath.compile("/svrl:schematron-output/svrl:failed-assert"); 72 | NodeList nl = (NodeList) expr.evaluate(result.getNode(), XPathConstants.NODESET); 73 | 74 | List> data = new ArrayList<>(); 75 | int fatalErrors = 0; 76 | int conditionalErrors = 0; 77 | int errors = 0; 78 | int conditionalFatalErrors = 0; 79 | if (nl.getLength() > 0) { 80 | for (int i = 0; i < nl.getLength(); i++) { 81 | String role = String.format("/svrl:schematron-output/svrl:failed-assert[%d]/@role", i + 1); 82 | String msg = String.format("/svrl:schematron-output/svrl:failed-assert[%d]/svrl:text", i + 1); 83 | XPathExpression exprMsg = xpath.compile(msg); 84 | XPathExpression exprRole = xpath.compile(role); 85 | 86 | Map failure = new HashMap<>(); 87 | if (exprRole.evaluate(result.getNode()).equalsIgnoreCase("Fatal Error")) { 88 | fatalErrors = fatalErrors + 1; 89 | } 90 | if (exprRole.evaluate(result.getNode()).equalsIgnoreCase("Conditional Error")) { 91 | conditionalErrors = conditionalErrors + 1; 92 | } 93 | if (exprRole.evaluate(result.getNode()).equalsIgnoreCase("Error")) { 94 | errors = errors + 1; 95 | } 96 | if (exprRole.evaluate(result.getNode()).equalsIgnoreCase("Conditional Fatal Error")) { 97 | conditionalFatalErrors = conditionalFatalErrors + 1; 98 | } 99 | failure.put("role", exprRole.evaluate(result.getNode())); 100 | failure.put("msg", exprMsg.evaluate(result.getNode())); 101 | data.add(failure); 102 | } 103 | 104 | Map errorCountMap = new HashMap<>(); 105 | errorCountMap.put("fatalErrors", String.valueOf(fatalErrors)); 106 | errorCountMap.put("conditionalErrors", String.valueOf(conditionalErrors)); 107 | errorCountMap.put("errors", String.valueOf(errors)); 108 | errorCountMap.put("conditionalFatalErrors", String.valueOf(conditionalFatalErrors)); 109 | data.add(errorCountMap); 110 | } else { 111 | Map errorCountMap = new HashMap<>(); 112 | errorCountMap.put("noError", "Message validates against Profile."); 113 | data.add(errorCountMap); 114 | } 115 | return data; 116 | 117 | } 118 | 119 | private NamespaceContext getNamespaceContext() { 120 | NamespaceContext ctx = new NamespaceContext() { 121 | @Override 122 | public String getNamespaceURI(String prefix) { 123 | if (prefix.equals("svrl")) { 124 | return "http://purl.oclc.org/dsdl/svrl"; 125 | } else { 126 | return null; 127 | } 128 | } 129 | 130 | @Override 131 | public String getPrefix(String namespaceURI) { 132 | return null; // not used 133 | } 134 | 135 | @Override 136 | public Iterator getPrefixes(String namespaceURI) { 137 | return null; // not used 138 | } 139 | }; 140 | return ctx; 141 | } 142 | 143 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/util/SchemaBuilder.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.util; 2 | 3 | import java.io.File; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | import javax.xml.XMLConstants; 9 | import javax.xml.transform.Source; 10 | import javax.xml.transform.stream.StreamSource; 11 | import javax.xml.validation.Schema; 12 | import javax.xml.validation.SchemaFactory; 13 | 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.stereotype.Component; 17 | import org.xml.sax.SAXException; 18 | 19 | import net.ddex.ern.exception.ValidatorException; 20 | import org.xml.sax.SAXNotRecognizedException; 21 | import org.xml.sax.SAXNotSupportedException; 22 | 23 | @Component 24 | public class SchemaBuilder { 25 | 26 | private static final Logger LOGGER = LoggerFactory.getLogger(SchemaBuilder.class); 27 | private static final String FILE_PATH_PREFIX = "schema/"; 28 | private ConcurrentHashMap schemaMap = new ConcurrentHashMap<>(); 29 | private SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 30 | 31 | // what happens when schema directory is empty 32 | public Schema getSchema(String schemaVersion) throws ValidatorException, SAXNotSupportedException, SAXNotRecognizedException { 33 | String schemaKey = schemaVersion.toLowerCase(); 34 | if (!schemaMap.containsKey(schemaKey)) { 35 | //List schemaFiles = Arrays.asList(env.getProperty(schemaKey).split("\\s*,\\s*")); 36 | List schemaFiles = loadSchemaFiles(schemaKey); 37 | Source[] sources = new Source[schemaFiles.size()]; 38 | factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); 39 | factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); 40 | for (int i = 0; i < schemaFiles.size(); i++) { 41 | sources[i] = new StreamSource(new File(String.format("%s/%s/%s", SchemaBuilder.FILE_PATH_PREFIX, schemaVersion, schemaFiles.get(i)))); 42 | } 43 | try { 44 | schemaMap.put(schemaKey, factory.newSchema(sources)); 45 | } catch (SAXException e) { 46 | LOGGER.error("SAXException while building Schema Object"); 47 | throw new ValidatorException(e.getMessage(), e); 48 | } 49 | } 50 | return schemaMap.get(schemaKey); 51 | } 52 | 53 | private List loadSchemaFiles(String schemaVersion) throws ValidatorException { 54 | File dir = new File(FILE_PATH_PREFIX + schemaVersion); 55 | if(!dir.isDirectory() || !dir.exists()) { 56 | throw new ValidatorException(schemaVersion + " is not a valid message version"); 57 | } 58 | return Arrays.asList(dir.list()); 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/vo/ValidationResponse.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by rdewilde on 5/16/2017. 9 | */ 10 | @JsonInclude(JsonInclude.Include.NON_EMPTY) 11 | public class ValidationResponse { 12 | 13 | private Boolean isError = false; 14 | private Boolean isSchemaValid; 15 | private Boolean isSchematronValid; 16 | 17 | private List schemaMessages; 18 | private List schematronMessages; 19 | 20 | private String status; 21 | private String message; 22 | 23 | public ValidationResponse(String status, String message) { 24 | this.isError = true; 25 | this.status = status; 26 | this.message = message; 27 | } 28 | 29 | public boolean isError() { 30 | return isError; 31 | } 32 | 33 | public void setError(Boolean error) { 34 | isError = error; 35 | } 36 | 37 | public Boolean isSchemaValid() { 38 | return isSchemaValid; 39 | } 40 | 41 | public void setSchemaValid(Boolean schemaValid) { 42 | isSchemaValid = schemaValid; 43 | } 44 | 45 | public Boolean isSchematronValid() { 46 | 47 | return isSchematronValid; 48 | } 49 | 50 | public void setSchematronValid(boolean schematronValid) { 51 | isSchematronValid = schematronValid; 52 | } 53 | 54 | public List getSchemaMessages() { 55 | return schemaMessages; 56 | } 57 | 58 | public void setSchemaMessages(List schemaMessages) { 59 | this.schemaMessages = schemaMessages; 60 | } 61 | 62 | public List getSchematronMessages() { 63 | return schematronMessages; 64 | } 65 | 66 | public void setSchematronMessages(List schematronMessages) { 67 | this.schematronMessages = schematronMessages; 68 | } 69 | 70 | public String getStatus() { 71 | return status; 72 | } 73 | 74 | public void setStatus(String status) { 75 | this.status = status; 76 | } 77 | 78 | public String getMessage() { 79 | return message; 80 | } 81 | 82 | public void setMessage(String message) { 83 | this.message = message; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/net/ddex/ern/vo/ValidationResult.java: -------------------------------------------------------------------------------- 1 | package net.ddex.ern.vo; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by rdewilde on 5/18/2017. 8 | */ 9 | public class ValidationResult { 10 | 11 | private Boolean isValid; 12 | private List messages = null; 13 | 14 | public Boolean getValid() { 15 | return isValid; 16 | } 17 | 18 | public void setValid(Boolean valid) { 19 | isValid = valid; 20 | } 21 | 22 | public List getMessages() { 23 | return messages; 24 | } 25 | 26 | public void setMessages(List messages) { 27 | this.messages = messages; 28 | } 29 | 30 | public void addMessage(String msg) { 31 | if (messages == null) { 32 | messages = new ArrayList<>(); 33 | } 34 | messages.add(msg); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | max.input.file.size.kb=15000 2 | releaseProfileVersion.map.schema={\ 3 | ern371 : 13, \ 4 | ern382 : 14, \ 5 | ern383 : 14, \ 6 | ern41 : 21, \ 7 | ern411 : 21 \ 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %d [%thread] %-5p %c - %m%n 8 | 9 | 10 | info 11 | 12 | 13 | 14 | true 15 | application.log 16 | 17 | %d %-4relative [%thread] %-5level %logger{35} - %msg%n 18 | 19 | 20 | application.log.%d{yyyy-MM-dd}.gz 21 | 90 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/main/schematron/commonreleasetypes/14/NewReleaseMessage_ReleaseProfile_MidiRingtone_14.sch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | Schematron Release Profile for Midi Ringtone (version 1.4) for the 10 | NewReleaseMessage. 11 | © 2006-2017 Digital Data Exchange, LLC (DDEX) 12 | This ISO Schematron file is, together with all DDEX standards, subject to two licences: If 13 | you wish to evaluate whether the standard meets your needs please have a look at the 14 | Evaluation Licence at https://kb.ddex.net/display/HBK/Evaluation+Licence+for+DDEX+Standards. 15 | If you want to implement and use this DDEX standard, please take out an Implementation 16 | Licence. For details please go to http://ddex.net/apply-ddex-implementation-licence. 17 | Failing a rule with a role of 'Fatal Error' means that the Conformance Tester must recommend 18 | to not award a Conformance Certificate or to retract a Conformance Certificate if one has 19 | already been issued. Failing a rule with a role of 'Conditional Fatal Error' is the same as a 20 | 'Fatal Error', however, the rule may be ignored if the Conformance Tester has no means of 21 | asserting whether the condition expressed in the rule has been met. 22 | Failing a rule a rule with a role of 'Error' means that the Conformance Tester must 23 | recommend to award a Partial Conformance Certificate or to downgrade a Conformance Certificate 24 | that has already been issued. However, if more than 1 rules (representing 50% of all rules 25 | with a role of 'Error' or 'Conditional Error') have been failed at least once, the Conformance 26 | Tester must recommend to not award a Conformance Certificate or to retract a Conformance 27 | Certificate if one has already been issued. Failing a rule with a role of 'Conditional Error' 28 | is the same as an 'Error', however, the rule may be ignored if the Conformance Tester has no 29 | means of asserting whether the condition expressed in the rule has been met. 30 | The following Clauses from the Release Profile standard are NOT checked by this ISO 31 | Schematron file: 3.3.1(1), 3.3.1(7)-(8), 3.4, 4.1, 4.2, 4.3(11), 4.3(14), 4.3(15a), 4.3(16b), 32 | 4.3(17), 4.3(19), 4.3(27)-(29), 4.3(37), 4.16(11)-(12), 4.7(11)-(12), 4.8(8), 4.8(9d), 33 | 4.8(10f), 4.8(11)-(12), 4.10(9) and similar clauses, 4.10(10) and similar clauses, 4.14(8) and 34 | 4.15(11). 35 | 36 | 37 | 38 | Fatal Error: #Midi Ringtone) The ReleaseProfileVersionId should be 40 | 'CommonReleaseTypes/14/Ringtone' (Release Profile 1.4, Clause 3.2, Rule 41 | 1364-1). 42 | 43 | 44 | 45 | 46 | 48 | Fatal Error: 49 | #Midi Ringtone) A Track Release must not contain more than one Resource (Release Profile 50 | 1.4, Clause 3.1, Rule 1365-1). 51 | 52 | 53 | 54 | 55 | 56 | Fatal Error: #Midi Ringtone) A Ringtone must contain one 59 | RingtoneRelease or RingbackToneRelease (Release Profile 1.4, Clause 3.1, Rule 60 | 1366-1). 61 | 62 | 63 | 64 | 65 | 66 | Fatal Error: 67 | #Midi Ringtone) At least one DisplayArtist shall be provided (Release Profile 1.4, 68 | Clause 4.3(12c)+4.3(15b), Rule 1367-1). 69 | 70 | 71 | 72 | 73 | 74 | Error: #Midi Ringtone) DisplayArtistNames for Release and Resource must be 77 | different (Release Profile 1.4, Clause 4.3(16a), Rule 1368-1). 78 | 79 | 80 | 81 | 82 | 83 | Fatal Error: #Midi Ringtone) The MainRelease shall be identified by 86 | either a GRid or by an ICPN (Release Profile 1.4, Clause 4.9(4), Rule 87 | 1369-1). 88 | 89 | 90 | 91 | 92 | 93 | Fatal Error: #Midi Ringtone) A Ringtone must contain a RelatedRelease 96 | of type IsReleaseFromRelease (Release Profile 1.4, Clause 4.9(9), Rule 97 | 1372-1). 98 | 99 | 100 | 101 | 102 | 103 | Information: #Midi Ringtone) No 104 | deprecated Flags (IsHiddenResource) must be provided for SoundRecordings (Release 105 | Profile 1.4, Clause 4.10(7h), Rule 1373-1). 106 | Information: #Midi Ringtone) No 107 | deprecated Flags (IsBonusResource) must be provided for SoundRecordings (Release Profile 108 | 1.4, Clause 4.10(7h), Rule 1373-2). 109 | 110 | 111 | 112 | 113 | 114 | Fatal Error: #Midi 115 | Ringtone) A LabelName has to be specified for each Release (Release Profile 1.4, 116 | Clause 4.13(8), Rule 1374-1). 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /src/main/schematron/commonreleasetypes/14/NewReleaseMessage_ReleaseProfile_SingleResourceRelease_14.sch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | Schematron Release Profile for Single Resource Release (version 1.4) for the 10 | NewReleaseMessage. 11 | © 2006-2017 Digital Data Exchange, LLC (DDEX) 12 | This ISO Schematron file is, together with all DDEX standards, subject to two licences: If 13 | you wish to evaluate whether the standard meets your needs please have a look at the 14 | Evaluation Licence at https://kb.ddex.net/display/HBK/Evaluation+Licence+for+DDEX+Standards. 15 | If you want to implement and use this DDEX standard, please take out an Implementation 16 | Licence. For details please go to http://ddex.net/apply-ddex-implementation-licence. 17 | Failing a rule with a role of 'Fatal Error' means that the Conformance Tester must recommend 18 | to not award a Conformance Certificate or to retract a Conformance Certificate if one has 19 | already been issued. Failing a rule with a role of 'Conditional Fatal Error' is the same as a 20 | 'Fatal Error', however, the rule may be ignored if the Conformance Tester has no means of 21 | asserting whether the condition expressed in the rule has been met. 22 | Failing a rule a rule with a role of 'Error' means that the Conformance Tester must 23 | recommend to award a Partial Conformance Certificate or to downgrade a Conformance Certificate 24 | that has already been issued. However, if more than 2 rules (representing 50% of all rules 25 | with a role of 'Error' or 'Conditional Error') have been failed at least once, the Conformance 26 | Tester must recommend to not award a Conformance Certificate or to retract a Conformance 27 | Certificate if one has already been issued. Failing a rule with a role of 'Conditional Error' 28 | is the same as an 'Error', however, the rule may be ignored if the Conformance Tester has no 29 | means of asserting whether the condition expressed in the rule has been met. 30 | The following Clauses from the Release Profile standard are NOT checked by this ISO 31 | Schematron file: 3.3.1(1), 3.3.1(7)-(8), 3.4, 4.1, 4.2, 4.3(11), 4.3(14), 4.3(15a), 4.3(16b), 32 | 4.3(17), 4.3(19), 4.3(27)-(29), 4.3(37), 4.16(11)-(12), 4.7(11)-(12), 4.8(8), 4.8(9d), 33 | 4.8(10f), 4.8(11)-(12), 4.10(9) and similar clauses, 4.10(10) and similar clauses, 4.14(8) and 34 | 4.15(11). 35 | 36 | 37 | 38 | Fatal Error: #Single Resource Release) The ReleaseProfileVersionId 40 | should be 'CommonReleaseTypes/14/SingleResourceRelease' (Release Profile 1.4, Clause 41 | 3.2, Rule 1463-1). 42 | 43 | 44 | 45 | 46 | 48 | Error: #Single Resource Release) Primary Video Resources should be 51 | identified with an ISRC (Release Profile 1.4, Clause 3.1, Rule 1464-1). 52 | 53 | 54 | 55 | 56 | 57 | Fatal Error: 58 | #Single Resource Release) A Single Resource Release must contain one (and only one) 59 | Resource (Release Profile 1.4, Clause 3.1, Rule 1465-1). 60 | 61 | 62 | 63 | 64 | 65 | Fatal Error: #Single Resource Release) A Single Resource Release must contain one 67 | SingleResourceRelease release (Release Profile 1.4, Clause 3.1, Rule 68 | 1466-1). 69 | 70 | 71 | 72 | 73 | 74 | Fatal Error: #Single 75 | Resource Release) A Single Resource Release must not contain a release resource 76 | structure (Release Profile 1.4, Clause 3.1, Rule 1467-1). 77 | 78 | 79 | 80 | 81 | 82 | Fatal Error: #Single Resource Release) A Single Resource Release must 85 | not contain any Secondary Resources (Release Profile 1.4, Clause 3.1, Rule 86 | 1468-1). 87 | 88 | 89 | 90 | 91 | 92 | Fatal Error: 93 | #Single Resource Release) At least one DisplayArtist shall be provided (Release Profile 94 | 1.4, Clause 4.3(12c)+4.3(15b), Rule 1469-1). 95 | 96 | 97 | 98 | 99 | 100 | Error: #Single Resource Release) DisplayArtistNames for Release and 103 | Resource must be different (Release Profile 1.4, Clause 4.3(16a), Rule 104 | 1470-1). 105 | 106 | 107 | 108 | 109 | 110 | Fatal Error: #Single Resource Release) The MainRelease shall be 113 | identified by either a GRid or by an ICPN (Release Profile 1.4, Clause 4.12(4), Rule 114 | 1471-1). 115 | 116 | 117 | 118 | 119 | 121 | Fatal Error: #Single Resource Release) Primary SoundRecording 124 | Resources shall be identified with an ISRC (Release Profile 1.4, Clause 4.12(5), Rule 125 | 1472-1). 126 | 127 | 128 | 129 | 130 | 132 | Fatal Error: #Single Resource Release) Secondary Resources shall be 135 | identified by a ProprietaryId (Release Profile 1.4, Clause 4.12(6), Rule 136 | 1473-1). 137 | 138 | 139 | 140 | 141 | 142 | Fatal Error: #Single Resource Release) A 143 | Single Resource Release must not contain any Resource Group (Release Profile 1.4, 144 | Clause 4.12(7), Rule 1474-1). 145 | 146 | 147 | 148 | 149 | 150 | Fatal Error: 151 | #Single Resource Release) A LabelName has to be specified for each Release (Release 152 | Profile 1.4, Clause 4.12(8), Rule 1475-1). 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /src/main/schematron/commonreleasetypes/21/NewReleaseMessage_ReleaseProfile_BoxedSetVariant_21.sch: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | Schematron Release Profile for Boxed Set Variant (version 2.1) for the NewReleaseMessage. 11 | © 2006-2018 Digital Data Exchange, LLC (DDEX) 12 | This ISO Schematron file is, together with all DDEX standards, subject to two licences: If you wish to evaluate whether the standard meets your needs please have a look at the Evaluation Licence at https://kb.ddex.net/display/HBK/Evaluation+Licence+for+DDEX+Standards. If you want to implement and use this DDEX standard, please take out an Implementation Licence. For details please go to http://ddex.net/apply-ddex-implementation-licence. 13 | Failing a rule with a role of 'Fatal Error' means that the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Fatal Error' is the same as a 'Fatal Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 14 | Failing a rule a rule with a role of 'Error' means that the Conformance Tester must recommend to award a Partial Conformance Certificate or to downgrade a Conformance Certificate that has already been issued. However, if more than 1 rules (representing 50% of all rules with a role of 'Error') have been failed at least once, the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Error' is the same as an 'Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 15 | The following Clauses from the Release Profile standard are NOT checked by this ISO Schematron file: 5.1.1 (partly), 5.3.1.1(1-3, 7.1, 7.3, 9), 5.3.1.2(2.1, 3-4, 5.1), 5.3.1.3(4-5), 5.3.1.4(3-5, 8), 5.3.3.1-2, 5.3.3.4, 5.4.1(4.1), 5.4.3(5), 5.4.4(3, 5), 5.5.1(2), 5.5.2(2.4, 3.5-3.7), 5.6(1, 3). This file also does not check any rules specified in the ERN Message Suite Standard (Version 4.1) specifications, sections 6.4 and 6.5, except for 6.4.8-10 16 | 17 | 18 | Fatal Error (Boxed Set Variant): The ReleaseProfileVariantVersionId should conform to clause 5.2.2 (Release Profile 2.1, Clause 5.2.2, Rule 1543-1). 20 | 21 | 22 | 23 | 24 | Fatal Error (Boxed Set Variant): For a Release of this type, second-level ResourceGroups shall have a ResourceGroupType of either Side, Component, ComponentRelease or ReleaseComponent (Release Profile 2.1, Clause 5.3.1.2(5.2), Rule 1544-1). 26 | 27 | 28 | 29 | 30 | Fatal Error (Boxed Set Variant): A Release of this type must contain at least two ResourceGroups of type ReleaseComponent (Release Profile 2.1, Clause 5.5.1(1), Rule 1545-1). 32 | 33 | 34 | 35 | 36 | Fatal Error (Boxed Set Variant): The identifier of the 'component' Releases that make up the Boxed Set Release shall be placed into the ReleaseId composite of the relevant ResourceGroup (Release Profile 2.1, Clause 5.5.1(3), Rule 1546-1). 37 | Fatal Error (Boxed Set Variant): The identifier of the 'component' Releases that make up the Boxed Set Release shall be identified by either a GRid or an ICPN (Release Profile 2.1, Clause 5.5.1(3), Rule 1546-2). 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main/schematron/commonreleasetypes/21/NewReleaseMessage_ReleaseProfile_ClassicalVariant_21.sch: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | Schematron Release Profile for Classical Variant (version 2.1) for the NewReleaseMessage. 11 | © 2006-2018 Digital Data Exchange, LLC (DDEX) 12 | This ISO Schematron file is, together with all DDEX standards, subject to two licences: If you wish to evaluate whether the standard meets your needs please have a look at the Evaluation Licence at https://kb.ddex.net/display/HBK/Evaluation+Licence+for+DDEX+Standards. If you want to implement and use this DDEX standard, please take out an Implementation Licence. For details please go to http://ddex.net/apply-ddex-implementation-licence. 13 | Failing a rule with a role of 'Fatal Error' means that the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Fatal Error' is the same as a 'Fatal Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 14 | Failing a rule a rule with a role of 'Error' means that the Conformance Tester must recommend to award a Partial Conformance Certificate or to downgrade a Conformance Certificate that has already been issued. However, if more than 1 rules (representing 50% of all rules with a role of 'Error') have been failed at least once, the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Error' is the same as an 'Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 15 | The following Clauses from the Release Profile standard are NOT checked by this ISO Schematron file: 5.1.1 (partly), 5.3.1.1(1-3, 7.1, 7.3, 9), 5.3.1.2(2.1, 3-4, 5.1), 5.3.1.3(4-5), 5.3.1.4(3-5, 8), 5.3.3.1-2, 5.3.3.4, 5.4.1(4.1), 5.4.3(5), 5.4.4(3, 5), 5.5.1(2), 5.5.2(2.4, 3.5-3.7), 5.6(1, 3). This file also does not check any rules specified in the ERN Message Suite Standard (Version 4.1) specifications, sections 6.4 and 6.5, except for 6.4.8-10 16 | 17 | 18 | Fatal Error (Classical Variant): The ReleaseProfileVariantVersionId should conform to clause 5.2.2 (Release Profile 2.1, Clause 5.2.2, Rule 1547-1). 20 | 21 | 22 | 23 | 24 | Fatal Error (Classical Variant): For a Release of this type, second-level ResourceGroups shall have a ResourceGroupType of either Side, Component or MultiWorkPart (Release Profile 2.1, Clause 5.3.1.2(5.2), Rule 1548-1). 26 | 27 | 28 | 29 | 30 | Fatal Error (Classical Variant): A Release of this type must contain SoundRecordings of type MusicalWorkSoundRecording (Release Profile 2.1, Clause 5.5.2(1), Rule 1549-1). 32 | 33 | 34 | 35 | 36 | Fatal Error (Classical Variant): A Release of this type must contain at least one ResourceGroup of type MultiWorkPart (Release Profile 2.1, Clause 5.5.2(2.1), Rule 1550-1). 38 | 39 | 40 | 41 | 42 | Conditional Fatal Error (Classical Variant): A Release of this type must contain at least two ResourceGroupContentItems in each ResourceGroup of type MultiWorkPart (Release Profile 2.1, Clause 5.5.2(2.2), Rule 1551-1). 44 | 45 | 46 | 47 | 48 | Fatal Error (Classical Variant): (Release Profile 2.1, Clause 5.5.2(2.5), Rule 1552-1). 50 | 51 | 52 | 53 | 54 | Warning (Classical Variant): A Resource in a Release of this type must contain an AdditionalTitle of type FormalTitle (Release Profile 2.1, Clause 5.5.2(3.1), Rule 1553-1). 55 | 56 | 57 | 58 | 59 | Warning (Classical Variant): A Resource in a Release of this type may contain an AdditionalTitle of type GroupingTitle (Release Profile 2.1, Clause 5.5.2(3.2), Rule 1554-1). 60 | 61 | 62 | 63 | 64 | Fatal Error (Classical Variant): A ResourceGroup in a Release of this type must contain a DisplayTitle and/or a DisplayTitleText (Release Profile 2.1, Clause 5.5.2(3.3), Rule 1555-1). 65 | 66 | 67 | 68 | 69 | Warning (Classical Variant): A ResourceGroup in a Release of this type shall contain an AdditionalTitle of type FormalTitle (Release Profile 2.1, Clause 5.5.2(3.4), Rule 1556-1). 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/main/schematron/commonreleasetypes/21/NewReleaseMessage_ReleaseProfile_ReleaseProfileTrackReleaseRules_21.sch: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | Schematron Release Profile for Release Profile Track Release Rules (version 2.1) for the NewReleaseMessage. 11 | © 2006-2018 Digital Data Exchange, LLC (DDEX) 12 | This ISO Schematron file is, together with all DDEX standards, subject to two licences: If you wish to evaluate whether the standard meets your needs please have a look at the Evaluation Licence at https://kb.ddex.net/display/HBK/Evaluation+Licence+for+DDEX+Standards. If you want to implement and use this DDEX standard, please take out an Implementation Licence. For details please go to http://ddex.net/apply-ddex-implementation-licence. 13 | Failing a rule with a role of 'Fatal Error' means that the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Fatal Error' is the same as a 'Fatal Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 14 | Failing a rule a rule with a role of 'Error' means that the Conformance Tester must recommend to award a Partial Conformance Certificate or to downgrade a Conformance Certificate that has already been issued. However, if more than 1 rules (representing 50% of all rules with a role of 'Error') have been failed at least once, the Conformance Tester must recommend to not award a Conformance Certificate or to retract a Conformance Certificate if one has already been issued. Failing a rule with a role of 'Conditional Error' is the same as an 'Error', however, the rule may be ignored if the Conformance Tester has no means of asserting whether the condition expressed in the rule has been met. 15 | 16 | 17 | Fatal Error (Release Profile Track Release Rules): A Release of this type must contain exactly one TrackRelease for each Primary Resource referenced in the Main Release (Release Profile 2.1, Clause 5.1.1(b), Rule 1538-1). 19 | 20 | 21 | 22 | 23 | Fatal Error (Release Profile Track Release Rules): An ISRC as an identifier for a TrackRelease shall be communicated as a ProprietaryId (Release Profile 2.1, Clause 5.3.1.3(3), Rule 1539-1). 24 | 25 | 26 | 27 | 28 | Fatal Error (Release Profile Track Release Rules): A TrackRelease must refer to one Primary Resource (Release Profile 2.1, Clause 5.6(2a), Rule 1540-1). 29 | 30 | 31 | 32 | 33 | Fatal Error (Release Profile Track Release Rules): A TrackRelease must not refer to a Secondary Resource (Release Profile 2.1, Clause 5.6(2b), Rule 1541-1). 35 | 36 | 37 | 38 | 39 | Error (Release Profile Track Release Rules): Title information for TrackReleases shall only be provided if it differs from the title information provided on the Resource (Release Profile 2.1, Clause 5.6(4), Rule 1542-1). 41 | Error (Release Profile Track Release Rules): Title information for TrackReleases shall only be provided if it differs from the title information provided on the Resource (Release Profile 2.1, Clause 5.6(4), Rule 1542-2). 43 | Error (Release Profile Track Release Rules): Title information for TrackReleases shall only be provided if it differs from the title information provided on the Resource (Release Profile 2.1, Clause 5.6(4), Rule 1542-3). 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/main/schematron/iso_abstract_expand.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 43 | 66 | 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 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 111 | 112 | 113 | 129 | 130 | 131 | 132 | Suppressed abstract pattern 133 | was here 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Start pattern based on abstract 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 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 194 | 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 | 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 | -------------------------------------------------------------------------------- /src/main/schematron/iso_svrl_for_xslt2.xsl: -------------------------------------------------------------------------------- 1 | 2 | 102 | 125 | 126 | 127 | 128 | 140 | 141 | 150 | 151 | 154 | 155 | 156 | 163 | 164 | true 165 | true 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | #ALL 177 | 178 | 179 | false 180 | true 181 | true 182 | 183 | 184 | 185 | 186 | false 187 | 188 | 189 | default 190 | 191 | 192 | 193 | 194 | 1 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | xslt1 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 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 | TERMINATING 321 | 322 | 323 | TERMINATING 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 | TERMINATING 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 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 | 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 | --------------------------------------------------------------------------------