EXIficientCodec.java 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package com.v2gclarity.risev2g.shared.exiCodec;
  2. /*******************************************************************************
  3. * The MIT License (MIT)
  4. *
  5. * Copyright (c) 2015-207 V2G Clarity (Dr.-Ing. Marc Mültin)
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. *******************************************************************************/
  25. import java.io.ByteArrayInputStream;
  26. import java.io.ByteArrayOutputStream;
  27. import java.io.IOException;
  28. import java.io.InputStream;
  29. import java.io.OutputStream;
  30. import java.io.StringWriter;
  31. import javax.xml.transform.Transformer;
  32. import javax.xml.transform.TransformerConfigurationException;
  33. import javax.xml.transform.TransformerException;
  34. import javax.xml.transform.TransformerFactory;
  35. import javax.xml.transform.sax.SAXSource;
  36. import javax.xml.transform.stream.StreamResult;
  37. import org.xml.sax.InputSource;
  38. import org.xml.sax.SAXException;
  39. import org.xml.sax.XMLReader;
  40. import org.xml.sax.helpers.XMLReaderFactory;
  41. import com.siemens.ct.exi.EXIFactory;
  42. import com.siemens.ct.exi.GrammarFactory;
  43. import com.siemens.ct.exi.api.sax.EXIResult;
  44. import com.siemens.ct.exi.api.sax.EXISource;
  45. import com.siemens.ct.exi.exceptions.EXIException;
  46. import com.siemens.ct.exi.grammars.Grammars;
  47. import com.siemens.ct.exi.helpers.DefaultEXIFactory;
  48. import com.v2gclarity.risev2g.shared.enumerations.GlobalValues;
  49. import com.v2gclarity.risev2g.shared.utils.ByteUtils;
  50. public final class EXIficientCodec extends ExiCodec {
  51. // -- BEGIN: SINGLETON DEFINITION --
  52. /*
  53. * Eager instantiation of the singleton, since a EXIficientCodec is always needed.
  54. * The JVM creates the unique instance when the class is loaded and before any thread tries to
  55. * access the instance variable -> thread safe.
  56. */
  57. private static final EXIficientCodec instance = new EXIficientCodec();
  58. private EXIFactory exiFactory;
  59. private GrammarFactory grammarFactory;
  60. private Grammars grammarAppProtocol;
  61. private Grammars grammarMsgDef;
  62. private Grammars grammarXMLDSig;
  63. private OutputStream encodeOS;
  64. private EXIficientCodec() {
  65. super();
  66. setExiFactory(DefaultEXIFactory.newInstance());
  67. setGrammarFactory(GrammarFactory.newInstance());
  68. /*
  69. * The Java classes
  70. * - EXIficient_V2G_CI_AppProtocol,
  71. * - EXIficient_V2G_CI_MsgDef, and
  72. * - EXIficient_xmldsig_core_schema
  73. * are serialized versions of the respective XSD schema files.
  74. * These serializations have been created using a tool available at
  75. * https://github.com/EXIficient/exificient-grammars/blob/master/src/main/java/com/siemens/ct/exi/grammars/persistency/Grammars2JavaSourceCode.java
  76. */
  77. setGrammarAppProtocol(new EXIficient_V2G_CI_AppProtocol());
  78. setGrammarMsgDef(new EXIficient_V2G_CI_MsgDef());
  79. setGrammarXMLDSig(new EXIficient_xmldsig_core_schema());
  80. // Non-default settings to fulfill requirements [V2G2-099] and [V2G2-600]
  81. getExiFactory().setValuePartitionCapacity(0);
  82. getExiFactory().setMaximumNumberOfBuiltInElementGrammars(0);
  83. getExiFactory().setMaximumNumberOfBuiltInProductions(0);
  84. }
  85. public static EXIficientCodec getInstance() {
  86. return instance;
  87. }
  88. // -- END: SINGLETON DEFINITION --
  89. @Override
  90. public synchronized byte[] encodeEXI(Object jaxbObject, String xsdSchemaPath) {
  91. Grammars grammar = null;
  92. if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_APP_PROTOCOL.toString()))
  93. grammar = getGrammarAppProtocol();
  94. else if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_MSG_DEF.toString()))
  95. grammar = getGrammarMsgDef();
  96. else if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_XMLDSIG.toString()))
  97. grammar = getGrammarXMLDSig();
  98. else {
  99. getLogger().error("False schema path provided for encoding jaxbObject into EXI");
  100. return null;
  101. }
  102. InputStream inStream = marshalToInputStream(jaxbObject);
  103. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  104. baos = ((ByteArrayOutputStream) encode(inStream, grammar));
  105. if (isHexAndBase64MsgRepresentation())
  106. showHexAndBase64RepresentationOfMessage(jaxbObject, baos.toByteArray());
  107. return baos.toByteArray();
  108. }
  109. private synchronized OutputStream encode(InputStream jaxbXML, Grammars grammar) {
  110. EXIResult exiResult = null;
  111. try {
  112. exiFactory.setGrammars(grammar);
  113. encodeOS = new ByteArrayOutputStream();
  114. exiResult = new EXIResult(exiFactory);
  115. exiResult.setOutputStream(encodeOS);
  116. XMLReader xmlReader = XMLReaderFactory.createXMLReader();
  117. xmlReader.setContentHandler(exiResult.getHandler());
  118. // parse xml file
  119. xmlReader.parse(new InputSource(jaxbXML));
  120. encodeOS.close();
  121. } catch (SAXException | IOException | EXIException e) {
  122. getLogger().error(e.getClass().getSimpleName() + " occurred while trying to encode", e);
  123. }
  124. return encodeOS;
  125. }
  126. @Override
  127. public synchronized Object decodeEXI(byte[] exiEncodedMessage, boolean supportedAppProtocolHandshake) {
  128. getLogger().debug("Received EXI stream: " + ByteUtils.toHexString(exiEncodedMessage));
  129. ByteArrayInputStream bais = new ByteArrayInputStream(exiEncodedMessage);
  130. setDecodedExi(decode(bais, supportedAppProtocolHandshake));
  131. return unmarshallToMessage(getDecodedExi());
  132. }
  133. private synchronized String decode(InputStream exiInputStream, boolean supportedAppProtocolHandshake) {
  134. TransformerFactory tf = TransformerFactory.newInstance();
  135. Transformer transformer = null;
  136. StringWriter stringWriter = new StringWriter();
  137. try {
  138. transformer = tf.newTransformer();
  139. } catch (TransformerConfigurationException e) {
  140. getLogger().error("Error occurred while trying to decode (TransformerConfigurationException)", e);
  141. }
  142. if (supportedAppProtocolHandshake) exiFactory.setGrammars(grammarAppProtocol);
  143. else exiFactory.setGrammars(grammarMsgDef);
  144. try {
  145. EXISource saxSource = new EXISource(exiFactory);
  146. SAXSource exiSource = new SAXSource(new InputSource(exiInputStream));
  147. XMLReader exiReader = saxSource.getXMLReader();
  148. exiSource.setXMLReader(exiReader);
  149. transformer.transform(exiSource, new StreamResult(stringWriter));
  150. } catch (EXIException e) {
  151. getLogger().error("Error occurred while trying to decode (EXIException)", e);
  152. } catch (TransformerException e) {
  153. getLogger().error("Error occurred while trying to decode (TransformerException)", e);
  154. }
  155. return stringWriter.toString();
  156. }
  157. private Grammars getGrammarAppProtocol() {
  158. return grammarAppProtocol;
  159. }
  160. private void setGrammarAppProtocol(Grammars grammarAppProtocol) {
  161. this.grammarAppProtocol = grammarAppProtocol;
  162. }
  163. private Grammars getGrammarMsgDef() {
  164. return grammarMsgDef;
  165. }
  166. private void setGrammarMsgDef(Grammars grammarMsgDef) {
  167. this.grammarMsgDef = grammarMsgDef;
  168. }
  169. public Grammars getGrammarXMLDSig() {
  170. return grammarXMLDSig;
  171. }
  172. public void setGrammarXMLDSig(Grammars grammarXMLDSig) {
  173. this.grammarXMLDSig = grammarXMLDSig;
  174. }
  175. public EXIFactory getExiFactory() {
  176. return exiFactory;
  177. }
  178. private void setExiFactory(EXIFactory exiFactory) {
  179. this.exiFactory = exiFactory;
  180. }
  181. @SuppressWarnings("unused")
  182. private GrammarFactory getGrammarFactory() {
  183. return grammarFactory;
  184. }
  185. private void setGrammarFactory(GrammarFactory grammarFactory) {
  186. this.grammarFactory = grammarFactory;
  187. }
  188. @Override
  189. public void setFragment(boolean useFragmentGrammar) {
  190. getExiFactory().setFragment(useFragmentGrammar);
  191. }
  192. }