View Javadoc

1   /**
2    * 
3    */
4   package org.appfuse.webapp.client.application;
5   
6   import static com.google.web.bindery.autobean.shared.AutoBeanUtils.getAutoBean;
7   
8   import java.util.HashMap;
9   import java.util.Map;
10  
11  import org.appfuse.webapp.client.proxies.UserProxy;
12  import org.appfuse.webapp.client.proxies.UsersSearchCriteriaProxy;
13  import org.appfuse.webapp.client.requests.ApplicationRequestFactory;
14  
15  import com.google.gwt.core.shared.GWT;
16  import com.google.inject.Inject;
17  import com.google.web.bindery.autobean.shared.AutoBean;
18  import com.google.web.bindery.autobean.shared.AutoBeanCodex;
19  import com.google.web.bindery.autobean.shared.AutoBeanFactory;
20  import com.google.web.bindery.requestfactory.shared.BaseProxy;
21  import com.google.web.bindery.requestfactory.shared.EntityProxy;
22  import com.google.web.bindery.requestfactory.shared.impl.AbstractRequestFactory;
23  import com.google.web.bindery.requestfactory.shared.impl.Constants;
24  
25  /**
26   * @author ivangsa
27   *
28   */
29  public class ApplicationProxyFactory {
30      private static final Map<Class<? extends EntityProxy>, Class<?>> SEARCH_CRITERIA_TYPES_MAP = new HashMap<Class<? extends EntityProxy>, Class<?>>();
31  
32      static {
33          // You need to map proxyClass - searchCriteria.getClass() here
34          // for automatic serialization of the search criteria to the history
35          // token, as
36          // there is no way to re-generate a class object, that is not an
37          // EntityProxy.class, from a token string
38          SEARCH_CRITERIA_TYPES_MAP.put(UserProxy.class, UsersSearchCriteriaProxy.class);
39      }
40  
41      //
42      public interface NonPublicProxyFactory extends AutoBeanFactory {
43          AutoBean<UsersSearchCriteriaProxy> searchCriteria();
44      }
45  
46      private NonPublicProxyFactory autoBeanFactory = GWT.create(NonPublicProxyFactory.class);
47      private final ApplicationRequestFactory requests;
48  
49      /**
50       * @param requests
51       */
52      @Inject
53      public ApplicationProxyFactory(ApplicationRequestFactory requests) {
54          super();
55          this.requests = requests;
56      }
57  
58      public Class<?> getSearchCriteriaTypeForProxy(Class<? extends EntityProxy> proxyType) {
59          return SEARCH_CRITERIA_TYPES_MAP.get(proxyType);
60      };
61  
62      /**
63       * 
64       * @param proxyType
65       * @return
66       */
67      public <T extends BaseProxy> T create(Class<T> proxyType) {
68          AutoBean<T> autoBean = autoBeanFactory.create(proxyType);
69          allocateId(autoBean);
70          return autoBean.as();
71      }
72  
73      public <T extends BaseProxy> T clone(T proxy) {
74          Class proxyType = getAutoBean(proxy).getType();
75          return (T) deserialize(proxyType, serialize(proxy));
76      }
77  
78      /**
79       * Serialized an object into a string.
80       * 
81       * It only provides serialization out-of-the-box for {@link BaseProxy}
82       * objects. You may need to provide your own serialization for your custom
83       * types.
84       * 
85       * @param object
86       * @return
87       */
88      public String serialize(Object object) {
89          if (object instanceof BaseProxy) {
90              return serializeProxy((BaseProxy) object);
91          }
92          // Provide here your own serialization
93          return "";
94      }
95  
96      /**
97       * Deserializes a string, previously serialized by
98       * {@link #serialize(Object)}, into its object form.
99       * 
100      * It only provides out-of-the-box deserialization for configured
101      * {@link BaseProxy} objects. You may need to provide your own serialization
102      * for your custom types.
103      * 
104      * @param type
105      * @param key
106      * @return
107      */
108     public Object deserialize(Class<?> type, String key) {
109         if (String.class.equals(type)) {
110             return key;
111         } else if (autoBeanFactory.create(type) != null) {
112             return deserializeProxy((Class<BaseProxy>) type, key);
113         }
114         // Provide here your own serialization
115         return null;
116     }
117 
118     /**
119      * 
120      * @param proxy
121      * @return
122      */
123     public <T extends BaseProxy> String serializeProxy(T proxy) {
124         try {
125             String serialized = AutoBeanCodex.encode(getAutoBean(proxy)).getPayload();
126             return base64encode(serialized);
127         } catch (Exception e) {
128             e.printStackTrace();// for dev mode
129             return "";
130         }
131     }
132 
133     /**
134      * 
135      * @param proxyType
136      * @param key
137      * @return
138      */
139     public <T extends BaseProxy> T deserializeProxy(Class<T> proxyType, String key) {
140         try {
141             T proxy = AutoBeanCodex.decode(autoBeanFactory, proxyType, base64decode(key)).as();
142             allocateId((AutoBean) getAutoBean(proxy));
143             return proxy;
144         } catch (Exception e) {
145             e.printStackTrace();// for dev mode
146             return null;
147         }
148     }
149 
150     public <T extends BaseProxy> AutoBean<T> allocateId(AutoBean<T> autoBean) {
151         Object id = ((AbstractRequestFactory) requests).allocateId(autoBean.getType());
152         autoBean.setTag(Constants.STABLE_ID, id);
153         return autoBean;
154     }
155 
156     /**
157      * 
158      * @param proxy
159      * @param frozen
160      */
161     public <T extends BaseProxy> void setFrozen(T proxy, boolean frozen) {
162         getAutoBean(proxy).setFrozen(frozen);
163     }
164 
165     // these don't work on <= IE8
166     // private static native String base64encode(String a) /*-{
167     // return window.btoa(a);
168     // }-*/;
169     //
170     // private static native String base64decode(String b) /*-{
171     // return window.atob(b);
172     // }-*/;
173 
174     private static String base64encode(String a) {
175         return Base64Coder.encodeString(a);
176     };
177 
178     private static String base64decode(String b) {
179         return Base64Coder.decodeString(b);
180     }
181 
182 }
183 
184 //
185 // http://www.source-code.biz/base64coder/java/Base64Coder.java.txt
186 //
187 // Copyright 2003-2010 Christian d'Heureuse, Inventec Informatik AG, Zurich,
188 // Switzerland
189 // www.source-code.biz, www.inventec.ch/chdh
190 //
191 // This module is multi-licensed and may be used under the terms
192 // of any of the following licenses:
193 //
194 // EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal
195 // LGPL, GNU Lesser General Public License, V2.1 or later,
196 // http://www.gnu.org/licenses/lgpl.html
197 // GPL, GNU General Public License, V2 or later,
198 // http://www.gnu.org/licenses/gpl.html
199 // AL, Apache License, V2.0 or later, http://www.apache.org/licenses
200 // BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php
201 // MIT, MIT License, http://www.opensource.org/licenses/MIT
202 //
203 // Please contact the author if you need another license.
204 // This module is provided "as is", without warranties of any kind.
205 
206 /**
207  * A Base64 encoder/decoder.
208  *
209  * <p>
210  * This class is used to encode and decode data in Base64 format as described in
211  * RFC 1521.
212  *
213  * <p>
214  * Project home page: <a
215  * href="http://www.source-code.biz/base64coder/java/">www.
216  * source-code.biz/base64coder/java</a><br>
217  * Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
218  * Multi-licensed: EPL / LGPL / GPL / AL / BSD / MIT.
219  */
220 class Base64Coder {
221 
222     // Mapping table from 6-bit nibbles to Base64 characters.
223     private static final char[] map1 = new char[64];
224     static {
225         int i = 0;
226         for (char c = 'A'; c <= 'Z'; c++)
227             map1[i++] = c;
228         for (char c = 'a'; c <= 'z'; c++)
229             map1[i++] = c;
230         for (char c = '0'; c <= '9'; c++)
231             map1[i++] = c;
232         map1[i++] = '+';
233         map1[i++] = '/';
234     }
235 
236     // Mapping table from Base64 characters to 6-bit nibbles.
237     private static final byte[] map2 = new byte[128];
238     static {
239         for (int i = 0; i < map2.length; i++)
240             map2[i] = -1;
241         for (int i = 0; i < 64; i++)
242             map2[map1[i]] = (byte) i;
243     }
244 
245     /**
246      * Encodes a string into Base64 format. No blanks or line breaks are
247      * inserted.
248      * 
249      * @param s
250      *            A String to be encoded.
251      * @return A String containing the Base64 encoded data.
252      */
253     public static String encodeString(String s) {
254         return new String(encode(s.getBytes()));
255     }
256 
257     /**
258      * Encodes a byte array into Base64 format. No blanks or line breaks are
259      * inserted in the output.
260      * 
261      * @param in
262      *            An array containing the data bytes to be encoded.
263      * @return A character array containing the Base64 encoded data.
264      */
265     public static char[] encode(byte[] in) {
266         return encode(in, 0, in.length);
267     }
268 
269     /**
270      * Encodes a byte array into Base64 format. No blanks or line breaks are
271      * inserted in the output.
272      * 
273      * @param in
274      *            An array containing the data bytes to be encoded.
275      * @param iLen
276      *            Number of bytes to process in <code>in</code>.
277      * @return A character array containing the Base64 encoded data.
278      */
279     public static char[] encode(byte[] in, int iLen) {
280         return encode(in, 0, iLen);
281     }
282 
283     /**
284      * Encodes a byte array into Base64 format. No blanks or line breaks are
285      * inserted in the output.
286      * 
287      * @param in
288      *            An array containing the data bytes to be encoded.
289      * @param iOff
290      *            Offset of the first byte in <code>in</code> to be processed.
291      * @param iLen
292      *            Number of bytes to process in <code>in</code>, starting at
293      *            <code>iOff</code>.
294      * @return A character array containing the Base64 encoded data.
295      */
296     public static char[] encode(byte[] in, int iOff, int iLen) {
297         int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
298         int oLen = ((iLen + 2) / 3) * 4; // output length including padding
299         char[] out = new char[oLen];
300         int ip = iOff;
301         int iEnd = iOff + iLen;
302         int op = 0;
303         while (ip < iEnd) {
304             int i0 = in[ip++] & 0xff;
305             int i1 = ip < iEnd ? in[ip++] & 0xff : 0;
306             int i2 = ip < iEnd ? in[ip++] & 0xff : 0;
307             int o0 = i0 >>> 2;
308             int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
309             int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
310             int o3 = i2 & 0x3F;
311             out[op++] = map1[o0];
312             out[op++] = map1[o1];
313             out[op] = op < oDataLen ? map1[o2] : '=';
314             op++;
315             out[op] = op < oDataLen ? map1[o3] : '=';
316             op++;
317         }
318         return out;
319     }
320 
321     /**
322      * Decodes a string from Base64 format. No blanks or line breaks are allowed
323      * within the Base64 encoded input data.
324      * 
325      * @param s
326      *            A Base64 String to be decoded.
327      * @return A String containing the decoded data.
328      * @throws IllegalArgumentException
329      *             If the input is not valid Base64 encoded data.
330      */
331     public static String decodeString(String s) {
332         return new String(decode(s));
333     }
334 
335     /**
336      * Decodes a byte array from Base64 format and ignores line separators, tabs
337      * and blanks. CR, LF, Tab and Space characters are ignored in the input
338      * data. This method is compatible with
339      * <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>.
340      * 
341      * @param s
342      *            A Base64 String to be decoded.
343      * @return An array containing the decoded data bytes.
344      * @throws IllegalArgumentException
345      *             If the input is not valid Base64 encoded data.
346      */
347     public static byte[] decodeLines(String s) {
348         char[] buf = new char[s.length()];
349         int p = 0;
350         for (int ip = 0; ip < s.length(); ip++) {
351             char c = s.charAt(ip);
352             if (c != ' ' && c != '\r' && c != '\n' && c != '\t')
353                 buf[p++] = c;
354         }
355         return decode(buf, 0, p);
356     }
357 
358     /**
359      * Decodes a byte array from Base64 format. No blanks or line breaks are
360      * allowed within the Base64 encoded input data.
361      * 
362      * @param s
363      *            A Base64 String to be decoded.
364      * @return An array containing the decoded data bytes.
365      * @throws IllegalArgumentException
366      *             If the input is not valid Base64 encoded data.
367      */
368     public static byte[] decode(String s) {
369         return decode(s.toCharArray());
370     }
371 
372     /**
373      * Decodes a byte array from Base64 format. No blanks or line breaks are
374      * allowed within the Base64 encoded input data.
375      * 
376      * @param in
377      *            A character array containing the Base64 encoded data.
378      * @return An array containing the decoded data bytes.
379      * @throws IllegalArgumentException
380      *             If the input is not valid Base64 encoded data.
381      */
382     public static byte[] decode(char[] in) {
383         return decode(in, 0, in.length);
384     }
385 
386     /**
387      * Decodes a byte array from Base64 format. No blanks or line breaks are
388      * allowed within the Base64 encoded input data.
389      * 
390      * @param in
391      *            A character array containing the Base64 encoded data.
392      * @param iOff
393      *            Offset of the first character in <code>in</code> to be
394      *            processed.
395      * @param iLen
396      *            Number of characters to process in <code>in</code>, starting
397      *            at <code>iOff</code>.
398      * @return An array containing the decoded data bytes.
399      * @throws IllegalArgumentException
400      *             If the input is not valid Base64 encoded data.
401      */
402     public static byte[] decode(char[] in, int iOff, int iLen) {
403         if (iLen % 4 != 0)
404             throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4.");
405         while (iLen > 0 && in[iOff + iLen - 1] == '=')
406             iLen--;
407         int oLen = (iLen * 3) / 4;
408         byte[] out = new byte[oLen];
409         int ip = iOff;
410         int iEnd = iOff + iLen;
411         int op = 0;
412         while (ip < iEnd) {
413             int i0 = in[ip++];
414             int i1 = in[ip++];
415             int i2 = ip < iEnd ? in[ip++] : 'A';
416             int i3 = ip < iEnd ? in[ip++] : 'A';
417             if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
418                 throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
419             int b0 = map2[i0];
420             int b1 = map2[i1];
421             int b2 = map2[i2];
422             int b3 = map2[i3];
423             if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
424                 throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
425             int o0 = (b0 << 2) | (b1 >>> 4);
426             int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
427             int o2 = ((b2 & 3) << 6) | b3;
428             out[op++] = (byte) o0;
429             if (op < oLen)
430                 out[op++] = (byte) o1;
431             if (op < oLen)
432                 out[op++] = (byte) o2;
433         }
434         return out;
435     }
436 
437     // Dummy constructor.
438     private Base64Coder() {
439     }
440 
441 } // end class Base64Coder