1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.transport.impl;
17
18 import org.fourthline.cling.model.Constants;
19 import org.fourthline.cling.model.XMLUtil;
20 import org.fourthline.cling.model.message.UpnpMessage;
21 import org.fourthline.cling.model.message.gena.IncomingEventRequestMessage;
22 import org.fourthline.cling.model.message.gena.OutgoingEventRequestMessage;
23 import org.fourthline.cling.model.meta.StateVariable;
24 import org.fourthline.cling.model.state.StateVariableValue;
25 import org.fourthline.cling.transport.spi.GENAEventProcessor;
26 import org.fourthline.cling.model.UnsupportedDataException;
27 import org.w3c.dom.Document;
28 import org.w3c.dom.Element;
29 import org.w3c.dom.Node;
30 import org.w3c.dom.NodeList;
31 import org.xml.sax.ErrorHandler;
32 import org.xml.sax.InputSource;
33 import org.xml.sax.SAXException;
34 import org.xml.sax.SAXParseException;
35
36 import javax.xml.parsers.DocumentBuilder;
37 import javax.xml.parsers.DocumentBuilderFactory;
38 import javax.xml.parsers.FactoryConfigurationError;
39
40 import java.io.StringReader;
41 import java.util.logging.Level;
42 import java.util.logging.Logger;
43
44
45
46
47
48
49 public class GENAEventProcessorImpl implements GENAEventProcessor, ErrorHandler {
50
51 private static Logger log = Logger.getLogger(GENAEventProcessor.class.getName());
52
53 protected DocumentBuilderFactory createDocumentBuilderFactory() throws FactoryConfigurationError {
54 return DocumentBuilderFactory.newInstance();
55 }
56
57 public void writeBody(OutgoingEventRequestMessage requestMessage) throws UnsupportedDataException {
58 log.fine("Writing body of: " + requestMessage);
59
60 try {
61
62 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
63 factory.setNamespaceAware(true);
64 Document d = factory.newDocumentBuilder().newDocument();
65 Element propertysetElement = writePropertysetElement(d);
66
67 writeProperties(d, propertysetElement, requestMessage);
68
69 requestMessage.setBody(UpnpMessage.BodyType.STRING, toString(d));
70
71 if (log.isLoggable(Level.FINER)) {
72 log.finer("===================================== GENA BODY BEGIN ============================================");
73 log.finer(requestMessage.getBody().toString());
74 log.finer("====================================== GENA BODY END =============================================");
75 }
76
77 } catch (Exception ex) {
78 throw new UnsupportedDataException("Can't transform message payload: " + ex.getMessage(), ex);
79 }
80 }
81
82 public void readBody(IncomingEventRequestMessage requestMessage) throws UnsupportedDataException {
83
84 log.fine("Reading body of: " + requestMessage);
85 if (log.isLoggable(Level.FINER)) {
86 log.finer("===================================== GENA BODY BEGIN ============================================");
87 log.finer(requestMessage.getBody() != null ? requestMessage.getBody().toString() : "null");
88 log.finer("-===================================== GENA BODY END ============================================");
89 }
90
91 String body = getMessageBody(requestMessage);
92 try {
93
94 DocumentBuilderFactory factory = createDocumentBuilderFactory();
95 factory.setNamespaceAware(true);
96 DocumentBuilder documentBuilder = factory.newDocumentBuilder();
97 documentBuilder.setErrorHandler(this);
98
99 Document d = documentBuilder.parse(
100 new InputSource(new StringReader(body))
101 );
102
103 Element propertysetElement = readPropertysetElement(d);
104
105 readProperties(propertysetElement, requestMessage);
106
107 } catch (Exception ex) {
108 throw new UnsupportedDataException("Can't transform message payload: " + ex.getMessage(), ex, body);
109 }
110 }
111
112
113
114 protected Element writePropertysetElement(Document d) {
115 Element propertysetElement = d.createElementNS(Constants.NS_UPNP_EVENT_10, "e:propertyset");
116 d.appendChild(propertysetElement);
117 return propertysetElement;
118 }
119
120 protected Element readPropertysetElement(Document d) {
121
122 Element propertysetElement = d.getDocumentElement();
123 if (propertysetElement == null || !getUnprefixedNodeName(propertysetElement).equals("propertyset")) {
124 throw new RuntimeException("Root element was not 'propertyset'");
125 }
126 return propertysetElement;
127 }
128
129
130
131 protected void writeProperties(Document d, Element propertysetElement, OutgoingEventRequestMessage message) {
132 for (StateVariableValue stateVariableValue : message.getStateVariableValues()) {
133 Element propertyElement = d.createElementNS(Constants.NS_UPNP_EVENT_10, "e:property");
134 propertysetElement.appendChild(propertyElement);
135 XMLUtil.appendNewElement(
136 d,
137 propertyElement,
138 stateVariableValue.getStateVariable().getName(),
139 stateVariableValue.toString()
140 );
141 }
142 }
143
144 protected void readProperties(Element propertysetElement, IncomingEventRequestMessage message) {
145 NodeList propertysetElementChildren = propertysetElement.getChildNodes();
146
147 StateVariable[] stateVariables = message.getService().getStateVariables();
148
149 for (int i = 0; i < propertysetElementChildren.getLength(); i++) {
150 Node propertysetChild = propertysetElementChildren.item(i);
151
152 if (propertysetChild.getNodeType() != Node.ELEMENT_NODE)
153 continue;
154
155 if (getUnprefixedNodeName(propertysetChild).equals("property")) {
156
157 NodeList propertyChildren = propertysetChild.getChildNodes();
158
159 for (int j = 0; j < propertyChildren.getLength(); j++) {
160 Node propertyChild = propertyChildren.item(j);
161
162 if (propertyChild.getNodeType() != Node.ELEMENT_NODE)
163 continue;
164
165 String stateVariableName = getUnprefixedNodeName(propertyChild);
166 for (StateVariable stateVariable : stateVariables) {
167 if (stateVariable.getName().equals(stateVariableName)) {
168 log.fine("Reading state variable value: " + stateVariableName);
169 String value = XMLUtil.getTextContent(propertyChild);
170 message.getStateVariableValues().add(
171 new StateVariableValue(stateVariable, value)
172 );
173 break;
174 }
175 }
176
177 }
178 }
179 }
180 }
181
182
183
184 protected String getMessageBody(UpnpMessage message) throws UnsupportedDataException {
185 if (!message.isBodyNonEmptyString())
186 throw new UnsupportedDataException(
187 "Can't transform null or non-string/zero-length body of: " + message
188 );
189 return message.getBodyString().trim();
190 }
191
192 protected String toString(Document d) throws Exception {
193
194 String output = XMLUtil.documentToString(d);
195 while (output.endsWith("\n") || output.endsWith("\r")) {
196 output = output.substring(0, output.length() - 1);
197 }
198
199 return output;
200 }
201
202 protected String getUnprefixedNodeName(Node node) {
203 return node.getPrefix() != null
204 ? node.getNodeName().substring(node.getPrefix().length() + 1)
205 : node.getNodeName();
206 }
207
208 public void warning(SAXParseException e) throws SAXException {
209 log.warning(e.toString());
210 }
211
212 public void error(SAXParseException e) throws SAXException {
213 throw e;
214 }
215
216 public void fatalError(SAXParseException e) throws SAXException {
217 throw e;
218 }
219 }
220