001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.http.rpc;
021 
022 import js.ArrayLike;
023 import js.Js;
024 import js.ObjectLike;
025 import js.Vars;
026 import jsx.core.ArrayLikes;
027 
028 /**
029  * <p>An abstract base class for an XML based serialization through HTTP context.</p>
030  * 
031  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
032  */
033 public abstract class XMLHttpContext extends HttpRemote.Context
034 {
035     /**
036      * <p>The tag name for arguments.</p>
037      * @since 1.0
038      */
039     protected final static String ARGS = "args";
040     /**
041      * <p>The tag name for base objects.</p>
042      * @since 1.0
043      */
044     protected final static String BASE = "base";
045     /**
046      * <p>The tag name for contexts.</p>
047      * @since 1.0
048      */
049     protected final static String CNTX = "cntx";
050     /**
051      * <p>The tag name for return value.</p>
052      * @since 1.0
053      */
054     protected final static String RTRN = "rtrn";
055     /**
056      * <p>The tag name for serialization ids.</p>
057      * @since 1.0
058      */
059     protected final static String SIDS = "sids";
060 
061     /**
062      * <p>The tag name for objects.</p>
063      * @since 1.0
064      */
065     protected final static String OBJ = "obj";
066     /**
067      * <p>The tag name for numbers.</p>
068      * @since 1.0
069      */
070     protected final static String NUM = "num";
071     /**
072      * <p>The tag name for strings.</p>
073      * @since 1.0
074      */
075     protected final static String STR = "str";
076     /**
077      * <p>The tag name for XML.</p>
078      * @since 1.0
079      */
080     protected final static String XML = "xml";
081     /**
082      * <p>The tag name for object fields.</p>
083      * @since 1.0
084      */
085     protected final static String FLD = "fld";
086     /**
087      * <p>The tag name for {@link js.Index} of object fields.</p>
088      * @since 1.0
089      */
090     protected final static String IDX = "idx";
091     /**
092      * <p>The tag name for field values.</p>
093      * @since 1.0
094      */
095     protected final static String VAL = "val";
096 
097     /**
098      * <p>The default constructor for the contexts of this class type.</p>
099      * <p>The constructor simply invokes the default constructor of the super class.</p>
100      * @since 1.0
101      */
102     protected XMLHttpContext() {
103         super();
104     }
105 
106     /**
107      * <p>Creates an XML document.</p>
108      * @param v The content of the document being created.
109      * @return The document.
110      * @since 1.0
111      */
112     protected static final String doc(String v) {
113         return Js.add("<?xml version=\"1.0\" encoding=\"utf-8\"?>", v);
114     }
115 
116     /**
117      * <p>Creates an XML element.</p>
118      * @param t The tag name of the XML element being created.
119      * @param v The content of the XML element being created.
120      * @return The XML element.
121      * @since 1.0
122      */
123     protected static final String xelt(String t, String v) {
124         return new Vars<String>().add("<").add(t).add(">").add(v)
125                                  .add("<").add("/").add(t).add(">")
126                                  .var().join("");
127     }
128 
129     /**
130      * <p>Creates an XML element representing an object field.</p>
131      * @param idx The {@link js.Index} of the field.
132      * @param val The value of the field.
133      * @return The XML element.
134      * @since 1.0
135      */
136     protected static final String fld(String idx, String val) {
137         return xelt(
138                 FLD,
139                 Js.add(
140                         xelt(IDX, idx),
141                         xelt(VAL, val)
142                 )
143         );
144     }
145 
146     private final static ArrayLike<String> tags = new Vars<String>().add(OBJ)
147                                                                     .add(NUM)
148                                                                     .add(STR).var();
149 
150     /**
151      * <p>Serializes an object to the specified depth into the current context.</p>
152      * @param o A number, string, {@link ObjectLike} or {@link HttpRemote}. 
153      * @return A serialization of the specified object. 
154      * @since 1.0
155      */
156     @Override
157     protected final String serialize(Object o, int depth) {
158         int t = type(o);
159         String tag = tags.get(t);
160         if (Js.be(t)) {
161             return xelt(tag, Js.toString(o));
162         }
163         if (depth < 1) {
164             return xelt(tag, sid(unwrap(o)));
165         }
166         String s = depth > 1 ? "" : xelt(SID, sid(unwrap(o)));
167         ArrayLike<String> ids = Js.keys(unwrap(o));
168         for (int i = 0, len = ArrayLikes.length(ids); i < len; i++) {
169             String id = ids.get(i);
170             if (Js.be(id) && id != SID) {
171                 String v = serialize(
172                         unwrap(o).var(id),
173                         depth - 1
174                 );
175                 s = depth > 1 ? Js.add(s, v) : Js.add(s, fld(id, v));
176             }
177         }
178         return depth > 1 ? s : xelt(tag, s);
179     }
180 }