package com.v2gclarity.risev2g.shared.exiCodec; /******************************************************************************* * The MIT License (MIT) * * Copyright (c) 2015-207 V2G Clarity (Dr.-Ing. Marc Mültin) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. *******************************************************************************/ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamResult; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; import com.siemens.ct.exi.EXIFactory; import com.siemens.ct.exi.GrammarFactory; import com.siemens.ct.exi.api.sax.EXIResult; import com.siemens.ct.exi.api.sax.EXISource; import com.siemens.ct.exi.exceptions.EXIException; import com.siemens.ct.exi.grammars.Grammars; import com.siemens.ct.exi.helpers.DefaultEXIFactory; import com.v2gclarity.risev2g.shared.enumerations.GlobalValues; import com.v2gclarity.risev2g.shared.utils.ByteUtils; public final class EXIficientCodec extends ExiCodec { // -- BEGIN: SINGLETON DEFINITION -- /* * Eager instantiation of the singleton, since a EXIficientCodec is always needed. * The JVM creates the unique instance when the class is loaded and before any thread tries to * access the instance variable -> thread safe. */ private static final EXIficientCodec instance = new EXIficientCodec(); private EXIFactory exiFactory; private GrammarFactory grammarFactory; private Grammars grammarAppProtocol; private Grammars grammarMsgDef; private Grammars grammarXMLDSig; private OutputStream encodeOS; private EXIficientCodec() { super(); setExiFactory(DefaultEXIFactory.newInstance()); setGrammarFactory(GrammarFactory.newInstance()); /* * The Java classes * - EXIficient_V2G_CI_AppProtocol, * - EXIficient_V2G_CI_MsgDef, and * - EXIficient_xmldsig_core_schema * are serialized versions of the respective XSD schema files. * These serializations have been created using a tool available at * https://github.com/EXIficient/exificient-grammars/blob/master/src/main/java/com/siemens/ct/exi/grammars/persistency/Grammars2JavaSourceCode.java */ setGrammarAppProtocol(new EXIficient_V2G_CI_AppProtocol()); setGrammarMsgDef(new EXIficient_V2G_CI_MsgDef()); setGrammarXMLDSig(new EXIficient_xmldsig_core_schema()); // Non-default settings to fulfill requirements [V2G2-099] and [V2G2-600] getExiFactory().setValuePartitionCapacity(0); getExiFactory().setMaximumNumberOfBuiltInElementGrammars(0); getExiFactory().setMaximumNumberOfBuiltInProductions(0); } public static EXIficientCodec getInstance() { return instance; } // -- END: SINGLETON DEFINITION -- @Override public synchronized byte[] encodeEXI(Object jaxbObject, String xsdSchemaPath) { Grammars grammar = null; if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_APP_PROTOCOL.toString())) grammar = getGrammarAppProtocol(); else if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_MSG_DEF.toString())) grammar = getGrammarMsgDef(); else if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_XMLDSIG.toString())) grammar = getGrammarXMLDSig(); else { getLogger().error("False schema path provided for encoding jaxbObject into EXI"); return null; } InputStream inStream = marshalToInputStream(jaxbObject); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos = ((ByteArrayOutputStream) encode(inStream, grammar)); if (isHexAndBase64MsgRepresentation()) showHexAndBase64RepresentationOfMessage(jaxbObject, baos.toByteArray()); return baos.toByteArray(); } private synchronized OutputStream encode(InputStream jaxbXML, Grammars grammar) { EXIResult exiResult = null; try { exiFactory.setGrammars(grammar); encodeOS = new ByteArrayOutputStream(); exiResult = new EXIResult(exiFactory); exiResult.setOutputStream(encodeOS); XMLReader xmlReader = XMLReaderFactory.createXMLReader(); xmlReader.setContentHandler(exiResult.getHandler()); // parse xml file xmlReader.parse(new InputSource(jaxbXML)); encodeOS.close(); } catch (SAXException | IOException | EXIException e) { getLogger().error(e.getClass().getSimpleName() + " occurred while trying to encode", e); } return encodeOS; } @Override public synchronized Object decodeEXI(byte[] exiEncodedMessage, boolean supportedAppProtocolHandshake) { getLogger().debug("Received EXI stream: " + ByteUtils.toHexString(exiEncodedMessage)); ByteArrayInputStream bais = new ByteArrayInputStream(exiEncodedMessage); setDecodedExi(decode(bais, supportedAppProtocolHandshake)); return unmarshallToMessage(getDecodedExi()); } private synchronized String decode(InputStream exiInputStream, boolean supportedAppProtocolHandshake) { TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = null; StringWriter stringWriter = new StringWriter(); try { transformer = tf.newTransformer(); } catch (TransformerConfigurationException e) { getLogger().error("Error occurred while trying to decode (TransformerConfigurationException)", e); } if (supportedAppProtocolHandshake) exiFactory.setGrammars(grammarAppProtocol); else exiFactory.setGrammars(grammarMsgDef); try { EXISource saxSource = new EXISource(exiFactory); SAXSource exiSource = new SAXSource(new InputSource(exiInputStream)); XMLReader exiReader = saxSource.getXMLReader(); exiSource.setXMLReader(exiReader); transformer.transform(exiSource, new StreamResult(stringWriter)); } catch (EXIException e) { getLogger().error("Error occurred while trying to decode (EXIException)", e); } catch (TransformerException e) { getLogger().error("Error occurred while trying to decode (TransformerException)", e); } return stringWriter.toString(); } private Grammars getGrammarAppProtocol() { return grammarAppProtocol; } private void setGrammarAppProtocol(Grammars grammarAppProtocol) { this.grammarAppProtocol = grammarAppProtocol; } private Grammars getGrammarMsgDef() { return grammarMsgDef; } private void setGrammarMsgDef(Grammars grammarMsgDef) { this.grammarMsgDef = grammarMsgDef; } public Grammars getGrammarXMLDSig() { return grammarXMLDSig; } public void setGrammarXMLDSig(Grammars grammarXMLDSig) { this.grammarXMLDSig = grammarXMLDSig; } public EXIFactory getExiFactory() { return exiFactory; } private void setExiFactory(EXIFactory exiFactory) { this.exiFactory = exiFactory; } @SuppressWarnings("unused") private GrammarFactory getGrammarFactory() { return grammarFactory; } private void setGrammarFactory(GrammarFactory grammarFactory) { this.grammarFactory = grammarFactory; } @Override public void setFragment(boolean useFragmentGrammar) { getExiFactory().setFragment(useFragmentGrammar); } }