| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /*******************************************************************************
- * 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.
- *******************************************************************************/
- package com.v2gclarity.risev2g.shared.exiCodec;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.StringWriter;
- import java.util.Base64;
- import javax.xml.bind.JAXBElement;
- import javax.xml.bind.JAXBException;
- import javax.xml.bind.Marshaller;
- import javax.xml.bind.Unmarshaller;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import com.v2gclarity.risev2g.shared.enumerations.GlobalValues;
- import com.v2gclarity.risev2g.shared.utils.ByteUtils;
- import com.v2gclarity.risev2g.shared.utils.MiscUtils;
- import com.v2gclarity.risev2g.shared.v2gMessages.appProtocol.SupportedAppProtocolReq;
- import com.v2gclarity.risev2g.shared.v2gMessages.appProtocol.SupportedAppProtocolRes;
- import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.V2GMessage;
- public abstract class ExiCodec {
- private Logger logger = LogManager.getLogger(this.getClass().getSimpleName());
- private Marshaller marshaller;
- private Unmarshaller unmarshaller;
- private InputStream inStream;
- private Object decodedMessage;
- private String decodedExi;
- private boolean xmlMsgRepresentation;
- private boolean hexAndBase64MsgRepresentation;
-
- public ExiCodec() {
- // Check if XML representation of sent messages is to be shown (for debug purposes)
- if ((boolean) MiscUtils.getPropertyValue("exi.messages.showxml"))
- setXMLMsgRepresentation(true);
- else
- setXMLMsgRepresentation(false);
-
- // Check if hexadecimal and Base64 representation of sent messages is to be shown (for debug purposes)
- if ((boolean) MiscUtils.getPropertyValue("exi.messages.showhex"))
- setHexAndBase64MsgRepresentation(true);
- else
- setHexAndBase64MsgRepresentation(false);
- }
-
-
- public InputStream marshalToInputStream(Object jaxbObject) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- try {
- if (getInStream() != null) getInStream().reset();
- getMarshaller().marshal(jaxbObject, baos);
-
- setInStream(new ByteArrayInputStream(baos.toByteArray()));
- baos.close();
-
- if (isXMLMsgRepresentation()) showXMLRepresentationOfMessage(jaxbObject);
- return getInStream();
- } catch (JAXBException | IOException e) {
- getLogger().error(e.getClass().getSimpleName() + " occurred while trying to marshal to InputStream from JAXBElement", e);
- return null;
- }
- }
-
-
- public Object unmarshallToMessage(String decodedExiString) {
- try {
- if (getInStream() != null) getInStream().reset();
- setInStream(new ByteArrayInputStream(decodedExiString.getBytes()));
- Object unmarhalledObject = getUnmarshaller().unmarshal(getInStream());
-
- if (isXMLMsgRepresentation()) showXMLRepresentationOfMessage(unmarhalledObject);
- return unmarhalledObject;
- } catch (IOException | JAXBException | RuntimeException e) {
- getLogger().error(e.getClass().getSimpleName() + " occurred while trying to unmarshall decoded message", e);
- return null;
- }
- }
-
-
- /**
- * Shows the XML representation of a marshalled or unmarshalled message object. This is useful for debugging
- * purposes.
- *
- * @param message The (un)marshalled message object
- */
- @SuppressWarnings("rawtypes")
- public void showXMLRepresentationOfMessage(Object message) {
- StringWriter sw = new StringWriter();
- String className = "";
-
- if (message instanceof V2GMessage) {
- className = ((V2GMessage) message).getBody().getBodyElement().getName().getLocalPart();
- } else if (message instanceof JAXBElement) {
- className = ((JAXBElement) message).getName().getLocalPart();
- } else if (message instanceof SupportedAppProtocolReq) {
- className = "SupportedAppProtocolReq";
- } else if (message instanceof SupportedAppProtocolRes) {
- className = "SupportedAppProtocolRes";
- } else {
- className = "marshalled JAXBElement";
- }
-
- try {
- getMarshaller().marshal(message, sw);
- getLogger().debug("XML representation of " + className + ":\n" + sw.toString());
- } catch (JAXBException e) {
- getLogger().error(e.getClass().getSimpleName() + " occurred while trying to show XML representation of " + className, e);
- }
- }
-
-
- @SuppressWarnings("rawtypes")
- public void showHexAndBase64RepresentationOfMessage(Object messageOrField, byte[] exiEncodedObject) {
- String className = "";
-
- if (messageOrField instanceof V2GMessage) {
- className = ((V2GMessage) messageOrField).getBody().getBodyElement().getName().getLocalPart();
- } else if (messageOrField instanceof JAXBElement) {
- className = ((JAXBElement) messageOrField).getName().getLocalPart();
- } else if (messageOrField instanceof SupportedAppProtocolReq) {
- className = "SupportedAppProtocolReq";
- } else if (messageOrField instanceof SupportedAppProtocolRes) {
- className = "SupportedAppProtocolRes";
- } else {
- className = " JAXBElement";
- }
-
- getLogger().debug("EXI encoded " + className + ": " + ByteUtils.toHexString(exiEncodedObject));
- getLogger().debug("Base64 encoded " + className + ": " + Base64.getEncoder().encodeToString(exiEncodedObject));
- }
-
-
- /**
- * Provides the EXI encoding of the header's SignedInfo element. The resulting byte array can then be used to
- * verify a signature.
- *
- * @param jaxbSignedInfo The SignedInfo element of the V2GMessage header, given as a JAXB element
- * @return The EXI encoding of the SignedInfo element given as a byte array
- */
- public byte[] getExiEncodedSignedInfo(JAXBElement jaxbSignedInfo) {
- // The schema-informed fragment grammar option needs to be used for EXI encodings in the header's signature
- setFragment(true);
-
- // The SignedInfo element must be encoded
- byte[] encodedSignedInfo = encodeEXI(
- jaxbSignedInfo,
- GlobalValues.SCHEMA_PATH_XMLDSIG.toString()
- );
-
- // Do not use the schema-informed fragment grammar option for other EXI encodings (message bodies)
- setFragment(false);
-
- return encodedSignedInfo;
- }
-
-
- public abstract byte[] encodeEXI(Object jaxbXML, String xsdSchemaPath);
-
- public abstract Object decodeEXI(byte[] exiEncodedMessage, boolean supportedAppProtocolHandshake);
- public abstract void setFragment(boolean useFragmentGrammar);
-
- public Marshaller getMarshaller() {
- return marshaller;
- }
- public void setMarshaller(Marshaller marshaller) {
- this.marshaller = marshaller;
- }
- public Unmarshaller getUnmarshaller() {
- return unmarshaller;
- }
- public void setUnmarshaller(Unmarshaller unmarshaller) {
- this.unmarshaller = unmarshaller;
- }
-
- public Logger getLogger() {
- return logger;
- }
- public Object getDecodedMessage() {
- return decodedMessage;
- }
- public void setDecodedMessage(Object decodedMessage) {
- this.decodedMessage = decodedMessage;
- }
- public String getDecodedExi() {
- return decodedExi;
- }
- public void setDecodedExi(String decodedExi) {
- this.decodedExi = decodedExi;
- }
- public InputStream getInStream() {
- return inStream;
- }
- public void setInStream(InputStream inStream) {
- this.inStream = inStream;
- }
-
-
- private void setXMLMsgRepresentation(boolean xmlMsgRepresentation) {
- this.xmlMsgRepresentation = xmlMsgRepresentation;
- }
-
- public boolean isXMLMsgRepresentation() {
- return xmlMsgRepresentation;
- }
- public boolean isHexAndBase64MsgRepresentation() {
- return hexAndBase64MsgRepresentation;
- }
- public void setHexAndBase64MsgRepresentation(boolean hexAndBase64MsgRepresentation) {
- this.hexAndBase64MsgRepresentation = hexAndBase64MsgRepresentation;
- }
- }
|