KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sync4j > framework > tools > WBXMLTools


1 /**
2  * Copyright (C) 2003-2005 Funambol
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18 package sync4j.framework.tools;
19
20 import java.io.*;
21 import java.util.Vector JavaDoc;
22
23 import org.kxml.parser.ParseEvent;
24 import org.kxml.parser.XmlParser;
25 import org.kxml.parser.Tag;
26 import org.kxml.wap.SyncMLWriter;
27 import org.kxml.wap.SyncMLParser;
28 import org.kxml.wap.WapExtensionEvent;
29 import org.kxml.Xml;
30 import org.kxml.Attribute;
31
32 import sync4j.framework.core.SyncML;
33 import sync4j.framework.core.Util;
34 import sync4j.framework.core.Sync4jException;
35
36 import org.jibx.runtime.*;
37 import org.jibx.runtime.impl.*;
38
39 import org.apache.commons.lang.StringUtils;
40
41 /**
42  * Utility class for WBXML stuff
43  *
44  * @author Stefano Fornari
45  * @version $Id: WBXMLTools.java,v 1.19 2005/03/04 13:38:33 harrie Exp $
46  */

47 public class WBXMLTools {
48
49     // --------------------------------------------------------------- Constants
50
public static final String JavaDoc WELL_KNOWN_NS = ",DevInf,";
51
52     // ------------------------------------------------------------ Private data
53
private static String JavaDoc verDTD;
54
55     // ---------------------------------------------------------- Public methods
56

57     /**
58      * Converts a string to a WBXML message.
59      *
60      * @param s the String to convert - NOT NULL
61      *
62      * @return the WBXML message
63      *
64      * @throws Sync4jException in case of parser errors
65      */

66     public static byte[] toWBXML(final String JavaDoc s)
67     throws Sync4jException {
68         SyncMLWriter writer = null;
69         try {
70             writer = new SyncMLWriter(verDTD);
71             XmlParser xml = new XmlParser(new StringReader(s));
72             traverseXML(xml, writer);
73         } catch (IOException e) {
74             throw new Sync4jException(e.getMessage(), e);
75         } finally {
76             if (writer != null) try {writer.close();} catch (Exception JavaDoc e) {}
77         }
78
79         return writer.getBytes();
80     }
81
82     /**
83      * Encodes a <i>Message</i> to WBXML
84      * <p>
85      * The message is fixed before encoding in order to get a converted message
86      * that makes sense. For instance, the Meta type of a Results element (if
87      * there is any), must be changed from <code>application/vnd.syncml-devinf+xml</code>
88      * to <code>application/vnd.syncml-devinf+wbxml</code>
89      *
90      * @param msg the message to encode
91      *
92      * @return the encoded stream of bytes (as a byte[] buffer).
93      *
94      * @throws Sync4jException in case of errors
95      */

96     public static byte[] toWBXML(SyncML msg)
97     throws Sync4jException {
98
99         verDTD = msg.getSyncHdr().getVerDTD().getValue();
100
101         try {
102
103             ByteArrayOutputStream bout = new ByteArrayOutputStream();
104
105             IBindingFactory f = BindingDirectory.getFactory(SyncML.class);
106             IMarshallingContext c = f.createMarshallingContext();
107             c.setIndent(0);
108             c.marshalDocument(msg, "UTF-8", null, bout);
109
110             String JavaDoc inputXml = new String JavaDoc(bout.toByteArray());
111
112             return toWBXML(inputXml);
113
114         } catch(Exception JavaDoc e) {
115             e.printStackTrace();
116         }
117         return null;
118     }
119
120     /**
121      * Converts a WBXML message into the corresponding XML message.
122      *
123      * The character set used for the encoding is determined by
124      * wbxml defined h set (see WBXM standard) and if it
125      * is not defined UTF-8 is ised.
126      * @param msg the message to convert - NOT NULL
127      *
128      * @return the XML message or NULL if an error occurred
129      *
130      * @throws Sync4jException in case of parser errors
131      */

132     public static String JavaDoc wbxmlToXml(final byte[] msg)
133     throws Sync4jException {
134         return wbxmlToXml(msg, null);
135     }
136
137     /**
138      * Converts a WBXML message into the corresponding XML message.
139      *
140      * @param msg the message to convert - NOT NULL
141      * @param charset the characte set used for the encoding. If the
142      * value is null, the character set defined in the wbxml is used
143      * otherwise, UTF-8 is ised.
144      *
145      * @return the XML message or NULL if an error occurred
146      *
147      * @throws Sync4jException in case of parser errors
148      */

149     public static String JavaDoc wbxmlToXml(final byte[] msg, String JavaDoc charset)
150     throws Sync4jException {
151
152         ByteArrayInputStream in = null;
153         try {
154             in = new ByteArrayInputStream(msg);
155
156             SyncMLParser parser = new SyncMLParser(in, charset);
157
158             return parseWBXML(parser);
159         } catch (Throwable JavaDoc t) {
160             throw new Sync4jException(t.getMessage(), t);
161         }
162     }
163
164     public static boolean isWellKnownNamespace(String JavaDoc ns) {
165         return (WELL_KNOWN_NS.indexOf(',' + ns + ',') >= 0);
166     }
167
168     // --------------------------------------------------------- Private methods
169
private static void traverseXML(XmlParser parser, SyncMLWriter writer) throws IOException {
170         //
171
// NOTE: when the namespace changes in one of the namespaces listed
172
// in WELL_KNOWN_NS, a well known document must be inserted;
173
// therefore a new inner writer is created when the tag is opened
174
// and its content flushed in the original writer when the tag is
175
// closed
176
//
177

178         boolean leave = false;
179
180         do {
181             ParseEvent event = parser.read();
182
183             switch (event.getType()) {
184                 case Xml.START_TAG:
185                     SyncMLWriter tagWriter = null;
186
187                     String JavaDoc name = event.getName();
188
189                     if (isWellKnownNamespace(name)) {
190                         tagWriter = new SyncMLWriter(((Tag)event).getNamespace(), verDTD);
191                     } else {
192                         tagWriter = writer;
193                     }
194
195                     // see API doc of StartTag for more access methods
196
tagWriter.startTag(name);
197                     traverseXML(parser, tagWriter); // recursion
198

199                     if (tagWriter != writer) {
200                         tagWriter.close();
201                         writer.writeOpaque(new String JavaDoc(tagWriter.getBytes()));
202                         tagWriter = null;
203                     }
204                     break;
205
206                 case Xml.END_TAG:
207                     writer.endTag();
208                     leave = true;
209                     break;
210
211                 case Xml.END_DOCUMENT:
212                     leave = true;
213                     break;
214
215                 case Xml.TEXT:
216                     writer.write(event.getText());
217                     break;
218
219                 case Xml.WHITESPACE:
220                     break;
221
222                 default:
223             }
224         } while (!leave);
225     }
226
227     private static String JavaDoc parseWBXML(SyncMLParser parser) throws IOException {
228         boolean[] inTag = new boolean[6];
229         return parseWBXML(parser, inTag);
230     }
231
232     private static String JavaDoc parseWBXML(SyncMLParser parser, boolean[] inTag) throws IOException{
233         /**
234          * inTag[0]: flag for tag <Put> or <Results>
235          * inTag[1]: flag for tag <Item> not in Put or Results
236          * inTag[2]: flag for tag <Data> (inside a Item not in Put or Results)
237          * inTag[3]: flag for tag <Cred>
238          * inTag[4]: set if tag Meta inside Cred contains "b64"
239          * inTag[5]: set if tag Meta inside Cred contains "auth-md5"
240          */

241         StringBuffer JavaDoc buf=new StringBuffer JavaDoc();
242         boolean leave = false;
243
244         String JavaDoc tagName = null;
245         String JavaDoc text = null;
246
247         do {
248             ParseEvent event = parser.read();
249             switch (event.getType()) {
250                 case Xml.START_TAG:
251                     tagName = event.getName();
252
253                     buf.append("<");
254                     buf.append(tagName);
255                     Vector JavaDoc attrs=event.getAttributes();
256                     if(attrs!=null){
257                         for(int i=0;i<attrs.size();i++){
258                             Attribute attr=(Attribute)attrs.elementAt(i);
259                             buf.append(" ");
260                             buf.append(attr.getName());
261                             buf.append("='");
262                             buf.append(attr.getValue());
263                             buf.append("'");
264                         }
265                     }
266                     buf.append(">");
267
268                     //
269
//This is util for replace the Data content if contains
270
//illegal character
271
//
272
if (!inTag[0]) {
273                         inTag[0] = ("Put".equals(tagName) || "Results".equals(tagName));
274                     }
275
276                     if (!inTag[0]) {
277                         if (!inTag[1]) {
278                             inTag[1] = "Item".equals(tagName);
279                         } else if (inTag[1]) {
280                             inTag[2] = "Data".equals(tagName);
281                         }
282                     }
283                     
284                     //
285
//This is util to establish if the auth-md5 credential are
286
//encoded in Base64
287
//
288
if (!inTag[3]) {
289                         inTag[3] = "Cred".equals(tagName);
290                     }
291                     
292                     text = parseWBXML(parser, inTag);
293                     
294                     if (inTag[3]) {
295                         if ("Meta".equals(tagName)) {
296                             inTag[4] = (text.indexOf("b64") >= 0);
297                             inTag[5] = (text.indexOf("auth-md5") >= 0);
298                             buf.append(text);
299                             text = parseWBXML(parser, inTag);
300                         }
301                     }
302
303                     buf.append(text);
304                     break;
305
306                 case Xml.END_TAG:
307                     if (tagName != null) {
308                         if (tagName.equals("Put") || tagName.equals("Results")) {
309                             if (inTag[0]) {
310                                 inTag[0] = false;
311                             }
312                         } else if (tagName.equals("Cred")) {
313                             if (inTag[3]) {
314                                 inTag[3] = false;
315                             }
316                         } else if (tagName.equals("Item")) {
317                             if (inTag[1]) {
318                                 inTag[1] = false;
319                             }
320                         } else if (tagName.equals("Data")) {
321                             if (inTag[2]) {
322                                 inTag[2] = false;
323                             }
324                         }
325                     }
326                     buf.append("</");
327                     buf.append(event.getName());
328                     buf.append(">");
329                     leave = true;
330                     break;
331
332                 case Xml.END_DOCUMENT:
333                     leave = true;
334                     break;
335
336                 case Xml.TEXT:
337                     text = event.getText();
338
339                     if (!inTag[0] && inTag[1] && inTag[2]) {
340                         text = replaceDataContent(text);
341                     }
342                     buf.append(text);
343                     break;
344
345                 case Xml.WAP_EXTENSION:
346                     text = event.getText();
347
348                     if (!inTag[0] && inTag[1] && inTag[2]) {
349                         text = replaceDataContent(text);
350                     }
351                     
352                     if (event instanceof WapExtensionEvent) {
353                         WapExtensionEvent e = (WapExtensionEvent)event;
354                         Object JavaDoc content = e.getContent();
355                         
356                         if (inTag[5] && !inTag[4] && content != null) {
357                             if (content instanceof byte[]) {
358                                 text = new String JavaDoc(Base64.encode((byte[])content));
359                             }
360                         }
361                     }
362
363                     buf.append(text);
364                     break;
365
366                 case Xml.WHITESPACE:
367                     break;
368
369                 default:
370             }
371         } while (!leave);
372
373         return buf.toString();
374     }
375
376     /**
377      * Replace not permitted characters with their HTML codification.
378      *
379      * @param text the data content
380      *
381      * @return text the data content modified
382      */

383     private static String JavaDoc replaceDataContent(String JavaDoc text) {
384         text = StringUtils.replace(text, "&", "&amp;");
385         text = StringUtils.replace(text, "<", "&lt;");
386         text = StringUtils.replace(text, ">", "&gt;");
387         text = StringUtils.replace(text, "\"", "&quot;");
388         return text;
389     }
390 }
391
Popular Tags