aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/plugins-event/plugins-event-protocol/plugins-event-protocol-xml/src/main/java/org/onap/policy/apex/plugins/event/protocol/xml/Apex2XmlEventConverter.java
blob: af4b7815a6599ec683eca7c724b2af6c70cd1851 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*-
 * ============LICENSE_START=======================================================
 *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
 *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
 * ================================================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 * ============LICENSE_END=========================================================
 */

package org.onap.policy.apex.plugins.event.protocol.xml;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.onap.policy.apex.plugins.event.protocol.xml.jaxb.ObjectFactory;
import org.onap.policy.apex.plugins.event.protocol.xml.jaxb.XMLApexEvent;
import org.onap.policy.apex.plugins.event.protocol.xml.jaxb.XMLApexEventData;
import org.onap.policy.apex.service.engine.event.ApexEvent;
import org.onap.policy.apex.service.engine.event.ApexEventException;
import org.onap.policy.apex.service.engine.event.ApexEventProtocolConverter;
import org.onap.policy.apex.service.engine.event.ApexEventRuntimeException;
import org.onap.policy.apex.service.parameters.eventprotocol.EventProtocolParameters;
import org.onap.policy.common.utils.resources.ResourceUtils;
import org.xml.sax.SAXException;

/**
 * The Class Apex2XMLEventConverter converts {@link ApexEvent} instances into string instances of {@link XMLApexEvent}
 * that are XML representations of Apex events defined in JAXB.
 *
 * @author Liam Fallon (liam.fallon@ericsson.com)
 */
public final class Apex2XmlEventConverter implements ApexEventProtocolConverter {

    private static final String MODEL_SCHEMA_NAME = "xml/apex-event.xsd";

    // XML Unmarshaller and marshaller and object factory for events
    private Unmarshaller unmarshaller;
    private Marshaller marshaller;
    private ObjectFactory objectFactory = new ObjectFactory();

    /**
     * Constructor to create the Apex to XML converter.
     *
     * @throws ApexEventException the apex event exception
     */
    public Apex2XmlEventConverter() throws ApexEventException {
        try {
            final URL schemaUrl = ResourceUtils.getUrlResource(MODEL_SCHEMA_NAME);
            final Schema apexEventSchema =
                    SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaUrl);

            final JAXBContext jaxbContext = JAXBContext.newInstance(XMLApexEvent.class);

            // Set up the unmarshaller to carry out validation
            unmarshaller = jaxbContext.createUnmarshaller();
            unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
            unmarshaller.setSchema(apexEventSchema);

            // Set up the marshaller
            marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setSchema(apexEventSchema);
        } catch (JAXBException | SAXException e) {
            throw new ApexEventException("Unable to set up marshalling and unmarshalling for XML events", e);
        }
    }

    /**
     * {@inheritDoc}.
     */
    @Override
    public void init(final EventProtocolParameters parameters) {
        // No initialization necessary on this class
    }

    /**
     * {@inheritDoc}.
     */
    @Override
    public List<ApexEvent> toApexEvent(final String eventName, final Object eventObject) throws ApexEventException {
        // Check the XML event
        if (eventObject == null) {
            throw new ApexEventException("event processing failed, XML event is null");
        }

        // Cast the event to a string, if our conversion is correctly configured, this cast should always work
        String xmlEventString = null;
        try {
            xmlEventString = (String) eventObject;
        } catch (final Exception e) {
            final String errorMessage = "error converting event \"" + eventObject + "\" to a string";
            throw new ApexEventRuntimeException(errorMessage, e);
        }

        // The XML event
        XMLApexEvent xmlApexEvent = null;

        // Use JAXB to read and verify the event from the XML string
        try {
            final StreamSource source = new StreamSource(new ByteArrayInputStream(xmlEventString.getBytes()));
            final JAXBElement<XMLApexEvent> rootElement = unmarshaller.unmarshal(source, XMLApexEvent.class);
            xmlApexEvent = rootElement.getValue();
        } catch (final JAXBException e) {
            throw new ApexEventException("Unable to unmarshal Apex XML event\n" + xmlEventString, e);
        }

        // Create the Apex event
        final ApexEvent apexEvent = new ApexEvent(xmlApexEvent.getName(), xmlApexEvent.getVersion(),
                xmlApexEvent.getNameSpace(), xmlApexEvent.getSource(), xmlApexEvent.getTarget());

        // Set the data on the apex event
        for (final XMLApexEventData xmlData : xmlApexEvent.getData()) {
            apexEvent.put(xmlData.getKey(), xmlData.getValue());
        }

        // Return the event in a single element
        final ArrayList<ApexEvent> eventList = new ArrayList<>();
        eventList.add(apexEvent);
        return eventList;
    }

    /**
     * {@inheritDoc}.
     */
    @Override
    public String fromApexEvent(final ApexEvent apexEvent) throws ApexEventException {
        // Check the Apex event
        if (apexEvent == null) {
            throw new ApexEventException("event processing failed, Apex event is null");
        }

        // Get the Apex event data
        final List<XMLApexEventData> xmlDataList = new ArrayList<>();

        try {
            for (final Entry<String, Object> apexDataEntry : apexEvent.entrySet()) {
                // Add an XML event data item
                if (apexDataEntry.getValue() != null) {
                    xmlDataList.add(new XMLApexEventData(apexDataEntry.getKey(), apexDataEntry.getValue().toString()));
                } else {
                    xmlDataList.add(new XMLApexEventData(apexDataEntry.getKey(), ""));
                }
            }
        } catch (final Exception e) {
            throw new ApexEventException("Unable to transfer Apex event data to XML\n" + apexEvent, e);
        }

        // Create the XML event
        final XMLApexEvent xmlApexEvent = new XMLApexEvent(apexEvent.getName(), apexEvent.getVersion(),
                apexEvent.getNameSpace(), apexEvent.getSource(), apexEvent.getTarget(), xmlDataList);

        // Write the event into a DOM document
        try {
            // Marshal the event into XML
            final StringWriter writer = new StringWriter();
            marshaller.marshal(objectFactory.createXmlApexEvent(xmlApexEvent), writer);

            // Return the event as XML in a string
            return writer.toString();
        } catch (final JAXBException e) {
            throw new ApexEventException("Unable to unmarshal Apex event to XML\n" + apexEvent, e);
        }
    }
}